/*
 *   khexedit - Versatile hex editor
 *   Copyright (C) 1999  Espen Sand, espensa@online.no
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program; if not, write to the Free Software
 *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <values.h>

#include <qbuttongroup.h>
#include <qcombobox.h>
#include <qcheckbox.h>
#include <qfileinfo.h> 
#include <qframe.h>
#include <qlabel.h>
#include <qlayout.h> 
#include <qlineedit.h>
#include <qpushbutton.h>
#include <qradiobutton.h>
#include <qspinbox.h>
#include <qtextstream.h> 

#include <kapp.h>
#include <kconfig.h>
#include <kfiledialog.h>
#include <klocale.h>
#include <kglobal.h>
#include <kmessagebox.h>
#include <kstddirs.h>

#include "dialog.h"
#include "listview.h"
#include "printerdialog.h"

#undef GrayScale


CPrinterDialog::CPrinterDialog( QWidget *parent, char *name, bool modal )
  :KDialogBase( Tabbed, i18n("Print Document"), Help|User2|User1|Cancel, User1,
	        parent, name, modal, false, i18n("&Print"), i18n("Pre&view") ),
   mPrinterColumnWidth( 125 )
{
  setHelp( "khexedit/khexedit.html", QString::null );

  mFrame[ page_destination ] = addPage( i18n("Destination") );
  mFrame[ page_option ] = addPage( i18n("Options") );
  mFrame[ page_layout ] = addPage( i18n("Page layout") );

  setupDestinationPage();
  setupOptionPage();
  setupLayoutPage();

  bool success = parsePrintcap();
  
  mConfig = 0;
  readConfiguration();

  QString path = mDestination.fileInput->text();
  int index = path.findRev( '/' );
  if( index != -1 ) { mWorkDir = path.left( index+1 ); }

  if( success == false )
  {
    //
    // I postpone an error message. The reason is that I dont want to 
    // display the message before the dialog box becomes visible. 
    // 
    startTimer( 100 );
  }

}


CPrinterDialog::~CPrinterDialog( void )
{
  writeConfiguration();
  delete mConfig; mConfig = 0;
}



void CPrinterDialog::resizeEvent( QResizeEvent * )
{
  setColumnWidth();
}


void CPrinterDialog::showEvent( QShowEvent *e )
{
  KDialogBase::showEvent(e);

  showPage(0);

  setColumnWidth();  
  const QListViewItem *entry = mDestination.printerList->selectedItem();
  if( entry != 0 )
  {
    mDestination.printerList->ensureItemVisible( entry );
  }
  
  if( mDestination.printerList->isEnabled() == true )
  {
    mDestination.printerList->setFocus();
  }
  else
  {
    mDestination.fileInput->setFocus();
  }

}


void CPrinterDialog::setColumnWidth( void )
{
  QListView *l= mDestination.printerList;
  int w0 = l->columnWidth(0) + l->columnWidth(1);
  int w1 = l->viewport()->width() - w0;
  l->setColumnWidth( 2, w1 );
}



void CPrinterDialog::readConfiguration( void )
{
  if( mConfig != 0 ) { return; }

  //
  // 1999-08-03-ES
  // Used to do this:
  // QString configPath = locate(QString("config"), QString("hexprinter") );
  // mConfig = new KSimpleConfig( configPath );
  // But if "hexprinter" does not exist then I have to use
  // KSimpleConfig( QString("hexprinter") ) anyway in order to be able to 
  // save config data later.
  //
  mConfig = new KSimpleConfig( QString("hexprinter") );
  if( mConfig == 0 ) { return; }


  mConfig->setGroup( "Destination" );
  
  bool state = mConfig->readBoolEntry( "PrintToFile", false );
  mDestination.fileCheck->setChecked( state );
  printFileCheck();
  QString text = mConfig->readEntry( "FileName" );
  mDestination.fileInput->setText( text );
  QString qText( mConfig->readEntry( "PrinterName" ) );
  setSelectedPrinter( qText );
  state = mConfig->readBoolEntry( "Postscript", true );
  mDestination.postscriptRadio->setChecked( state );
  mDestination.textRadio->setChecked( state == true ? false : true );
  textFormatClicked( state == true ? 0 : 1 );

  mConfig->setGroup( "Option" );
  state = mConfig->readBoolEntry( "Portrait", true );
  mOption.portraitRadio->setChecked( state );
  mOption.landscapeRadio->setChecked( state == true ? false : true );
  text = mConfig->readEntry( "PaperType", "A4" );
  comboMatchText( mOption.paperSelector, text );
  paperTypeChanged( mOption.paperSelector->currentItem() );

  state = mConfig->readBoolEntry( "ScaleToFit", true );
  mOption.scaleCheck->setChecked( state );
  int val = mConfig->readNumEntry( "NumberOfCopies", 1 );
  mOption.pageSpin->setValue( val );
 
  state = mConfig->readBoolEntry( "FirstPageFirst", true );
  mOption.firstRadio->setChecked( state );
  mOption.lastRadio->setChecked( state == true ? false : true );
  text = mConfig->readEntry( "PreviewApplication", "kghostview" );
  mOption.previewInput->setText( text );


  text = mConfig->readEntry( "Color" );
  if( text == QString("color") )
  {
    mOption.colorGroup->setButton( 0 );
  }
  else if( text == QString("gray") )
  {
    mOption.colorGroup->setButton( 1 );
  }
  else if( text == QString("blackWhite") )
  {
    mOption.colorGroup->setButton( 2 );
  }
  else
  {
    mOption.colorGroup->setButton( 0 );
  }

  mConfig->setGroup( "PageLayout" );
  val = mConfig->readNumEntry( "MarginTop", 15 );
  mLayout.marginSpin[0]->setValue( val );
  val = mConfig->readNumEntry( "MarginBottom", 15 );
  mLayout.marginSpin[1]->setValue( val );
  val = mConfig->readNumEntry( "MarginLeft", 15 );
  mLayout.marginSpin[2]->setValue( val );
  val = mConfig->readNumEntry( "MarginRight", 15 );
  mLayout.marginSpin[3]->setValue( val );
  state = mConfig->readBoolEntry( "DrawHeader", true );
  mLayout.headerCheck->setChecked( state );
  slotDrawHeader( state );
  state = mConfig->readBoolEntry( "DrawFooter", true );
  mLayout.footerCheck->setChecked( state );
  slotDrawFooter( state );

  mLayout.headerCombo[0]->setCurrentItem(
    headerTextIndex( mConfig->readEntry("HeaderLeft","DateTime")));
  mLayout.headerCombo[1]->setCurrentItem(
    headerTextIndex( mConfig->readEntry("HeaderCenter")));
  mLayout.headerCombo[2]->setCurrentItem(
    headerTextIndex( mConfig->readEntry("HeaderRight","FileName")));
  mLayout.headerCombo[3]->setCurrentItem(
    headerLineIndex( mConfig->readEntry("HeaderLine","SingleLine")));

  mLayout.footerCombo[0]->setCurrentItem(
    headerTextIndex( mConfig->readEntry("FooterLeft")));
  mLayout.footerCombo[1]->setCurrentItem(
    headerTextIndex( mConfig->readEntry("FooterCenter","PageNumber")));
  mLayout.footerCombo[2]->setCurrentItem(
    headerTextIndex( mConfig->readEntry("FooterRight")));
  mLayout.footerCombo[3]->setCurrentItem(
    headerLineIndex( mConfig->readEntry("FooterLine","SingleLine")));

}

void CPrinterDialog::writeConfiguration( void )
{
  if( mConfig == 0 )
  {
    return;
  }

  mConfig->setGroup( "Destination" );
  mConfig->writeEntry( "PrintToFile", 
    mDestination.fileCheck->isChecked() );
  mConfig->writeEntry( "FileName", 
    mDestination.fileInput->text() );
  QListViewItem *listItem = mDestination.printerList->currentItem();
  mConfig->writeEntry( "PrinterName", 
    listItem == 0 ? QString("") : listItem->text(0) );
  mConfig->writeEntry( "Postscript", 
    mDestination.postscriptRadio->isChecked() );

  mConfig->setGroup( "Option" );
  mConfig->writeEntry( "Portrait", 
    mOption.portraitRadio->isChecked() );
  mConfig->writeEntry( "PaperType", 
    mOption.paperSelector->currentText() );
  mConfig->writeEntry( "ScaleToFit", 
    mOption.scaleCheck->isChecked() );
  mConfig->writeEntry( "NumberOfCopies", 
    mOption.pageSpin->value() );
  mConfig->writeEntry( "FirstPageFirst", 
    mOption.firstRadio->isChecked() );
  mConfig->writeEntry( "PreviewApplication", 
    mOption.previewInput->text() );
  if( mOption.colorRadio->isChecked() == true )
  {
    mConfig->writeEntry( "Color", "color" );
  }
  else if( mOption.grayRadio->isChecked() == true )
  {
    mConfig->writeEntry( "Color", "gray" );
  }
  else
  {
    mConfig->writeEntry( "Color", "blackWhite" );
  }

  mConfig->setGroup( "PageLayout" );
  mConfig->writeEntry( "MarginTop", mLayout.marginSpin[0]->value() );
  mConfig->writeEntry( "MarginBottom", mLayout.marginSpin[1]->value() );
  mConfig->writeEntry( "MarginLeft", mLayout.marginSpin[2]->value() );
  mConfig->writeEntry( "MarginRight", mLayout.marginSpin[3]->value() );
  mConfig->writeEntry( "DrawHeader", mLayout.headerCheck->isChecked() );
  mConfig->writeEntry( "DrawFooter", mLayout.footerCheck->isChecked() );

  mConfig->writeEntry( "HeaderLeft", 
    headerText( mLayout.headerCombo[0]->currentItem() ) );
  mConfig->writeEntry( "HeaderCenter",
    headerText( mLayout.headerCombo[1]->currentItem() ) );
  mConfig->writeEntry( "HeaderRight",
    headerText( mLayout.headerCombo[2]->currentItem() ) );
  mConfig->writeEntry( "HeaderLine",
    headerLine( mLayout.headerCombo[3]->currentItem() ) );

  mConfig->writeEntry( "FooterLeft",
    headerText( mLayout.footerCombo[0]->currentItem() ) );
  mConfig->writeEntry( "FooterCenter",
    headerText( mLayout.footerCombo[1]->currentItem() ) );
  mConfig->writeEntry( "FooterRight",
    headerText( mLayout.footerCombo[2]->currentItem() ) );
  mConfig->writeEntry( "FooterLine",
    headerLine( mLayout.footerCombo[3]->currentItem() ) );

  mConfig->sync();
}


QString CPrinterDialog::headerText( uint index )
{
  static const QString text[4] = {"None","DateTime","PageNumber","FileName"};
  return( text[ index > 3 ? 0 : index ] );
}


int CPrinterDialog::headerTextIndex( const QString & headerText )
{
  static const QString text[4] = {"None","DateTime","PageNumber","FileName"};
  if( headerText != 0 )
  {
    for( int i=0; i<4; i++ )
    {
      if( headerText == text[i] ) { return( i ); }
    }
  }  
  return( 0 );
}


QString CPrinterDialog::headerLine( uint index )
{
  static const QString text[3] = {"None","SingleLine","Rectangle"};
  return( text[ index > 2 ? 0 : index ] );
}


int CPrinterDialog::headerLineIndex( const QString & headerLine )
{
  static const QString text[3] = {"None","SingleLine","Rectangle"};
  if( headerLine != 0 )
  {
    for( int i=0; i<3; i++ )
    {
      if( headerLine == text[i] ) { return( i ); }
    }
  }  
  return( 0 );
}

void CPrinterDialog::setupDestinationPage( void )
{
  QString text;
  QFrame *page = mFrame[ page_destination ];

  QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );
  if( topLayout == 0 ) { return; }

  mDestination.printerList = new CListView( page, "printerList" );
  mDestination.printerList->setAllColumnsShowFocus( true );
  mDestination.printerList->addColumn( i18n("Printer"), mPrinterColumnWidth );
  mDestination.printerList->addColumn( i18n("Host"), mPrinterColumnWidth );
  mDestination.printerList->addColumn( i18n("Comment"), mPrinterColumnWidth );
  mDestination.printerList->setFrameStyle( QFrame::WinPanel + QFrame::Sunken );
  mDestination.printerList->setVisibleItem(4);

  text = i18n("&Available printers"); 
  mDestination.printerLabel = new QLabel( mDestination.printerList,text,page );
  topLayout->addWidget( mDestination.printerLabel );
  topLayout->addWidget( mDestination.printerList, 10 );

  text = i18n("Print to fi&le");
  mDestination.fileCheck = new QCheckBox( text, page );
  topLayout->addWidget( mDestination.fileCheck );
  connect( mDestination.fileCheck, SIGNAL(clicked()), SLOT(printFileCheck()) );

 
  QHBoxLayout *hbox = new QHBoxLayout();
  if( hbox == 0 ) { return; }
  topLayout->addLayout( hbox );

  mDestination.fileInput = new QLineEdit( page );
  hbox->addWidget( mDestination.fileInput, 10 );

  text = i18n("Choose...");
  mDestination.browseButton = new QPushButton( text, page, "browse" );
  mDestination.browseButton->setAutoDefault( false );
  hbox->addWidget( mDestination.browseButton );
  connect( mDestination.browseButton, SIGNAL(clicked()),
	   SLOT(browserClicked()) );

  QGridLayout *gbox = new QGridLayout( 1, 2, spacingHint() );
  if( gbox == 0 ) { return; }
  topLayout->addLayout( gbox );

  QButtonGroup *group = new QButtonGroup( i18n("Print range"), page );
  if( group == 0 ) { return; }
  gbox->addWidget( group, 0, 0 );

  QVBoxLayout *vbox = new QVBoxLayout( group, spacingHint() );  
  vbox->addSpacing( group->fontMetrics().height() );
  
  mDestination.allRadio = new QRadioButton( i18n("&Everything"), group );
  mDestination.allRadio->setFixedSize( mDestination.allRadio->sizeHint() );
  group->insert( mDestination.allRadio, 0 );
  vbox->addWidget( mDestination.allRadio, 0, AlignLeft );

  mDestination.selectRadio = new QRadioButton( i18n("&Selection"), group);
  mDestination.selectRadio->setFixedSize(mDestination.selectRadio->sizeHint());
  group->insert( mDestination.selectRadio, 1 );
  vbox->addWidget( mDestination.selectRadio, 0, AlignLeft );

  mDestination.rangeRadio = new QRadioButton( i18n("&Range"), group );
  mDestination.rangeRadio->setFixedSize( mDestination.rangeRadio->sizeHint() );
  group->insert( mDestination.rangeRadio, 2 );
  vbox->addWidget( mDestination.rangeRadio, 0, AlignLeft );

  QGridLayout *rbox = new QGridLayout( 2, 2, spacingHint() );
  vbox->addLayout( rbox );

  mDestination.fromInput = new QLineEdit( group );
  text = i18n("&From offset"); 
  mDestination.fromLabel = new QLabel( mDestination.fromInput, text, group );  
  rbox->addWidget( mDestination.fromLabel, 0, 0 );
  rbox->addWidget( mDestination.fromInput, 0, 1 );

  mDestination.toInput = new QLineEdit( group );
  text = i18n("&To offset"); 
  mDestination.toLabel = new QLabel( mDestination.toInput, text, group );
  rbox->addWidget( mDestination.toLabel, 1, 0 );
  rbox->addWidget( mDestination.toInput, 1, 1 );

  connect( group, SIGNAL(clicked(int)), SLOT(printRangeClicked(int)) );


  group = new QButtonGroup( i18n("Text formatting"), page );
  if( group == 0 ) { return; }
  gbox->addWidget( group, 0, 1 );

  vbox = new QVBoxLayout( group, spacingHint() );  
  vbox->addSpacing( group->fontMetrics().height() );
  
  text = i18n("Print as postscr&ipt");
  mDestination.postscriptRadio = new QRadioButton( text, group );
  mDestination.postscriptRadio->setFixedSize( 
    mDestination.postscriptRadio->sizeHint() );
  group->insert( mDestination.postscriptRadio, 0 );
  vbox->addWidget( mDestination.postscriptRadio, 0, AlignLeft );

  text = i18n("Print as plain &text");
  mDestination.textRadio = new QRadioButton( text, group );
  mDestination.textRadio->setFixedSize( mDestination.textRadio->sizeHint() );
  group->insert( mDestination.textRadio, 1 );
  vbox->addWidget( mDestination.textRadio, 0, AlignLeft );
  
  hbox = new QHBoxLayout();
  vbox->addLayout( hbox );
  
  text = i18n(""
    "This choice will ignore\n"
    "certain options. Refer to\n"
    "help for more information.");

  mDestination.helpLabel = new QLabel( text, group );
  mDestination.helpLabel->setFrameStyle( QFrame::Panel | QFrame::Sunken );
  mDestination.helpLabel->setFixedSize( mDestination.helpLabel->sizeHint() );
  mDestination.helpLabel->setAlignment( AlignBottom | AlignLeft );
  hbox->addSpacing( spacingHint() );
  hbox->addWidget( mDestination.helpLabel, 0, AlignCenter );
  hbox->addSpacing( spacingHint() );

  connect( group, SIGNAL(clicked(int)), SLOT(textFormatClicked(int)) );

  vbox->addStretch();

  mDestination.fileCheck->setChecked( false );
  printFileCheck();
  mDestination.allRadio->setChecked( true );
  printRangeClicked( 0 );
  mDestination.postscriptRadio->setChecked( true );
  textFormatClicked( 0 );
}

void CPrinterDialog::setupOptionPage( void )
{
  QString text;
  QFrame *page = mFrame[ page_option ];

  QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );  
  if( topLayout == 0 ) { return; }

  QGridLayout *gbox = new QGridLayout( 1, 2, spacingHint() );
  if( gbox == 0 ) { return; }
  topLayout->addLayout( gbox );

  mOption.oriGroup = new QButtonGroup( i18n("Orientation"), page );
  if( mOption.oriGroup == 0 ) { return; }
  gbox->addWidget( mOption.oriGroup, 0, 0 );

  QVBoxLayout *vbox = new QVBoxLayout( mOption.oriGroup, spacingHint() );
  vbox->addSpacing( mOption.oriGroup->fontMetrics().height() );
  
  text = i18n("Por&trait");
  mOption.portraitRadio = new QRadioButton( text, mOption.oriGroup );
  mOption.portraitRadio->setFixedSize( mOption.portraitRadio->sizeHint() );
  mOption.oriGroup->insert( mOption.portraitRadio, 0 );
  vbox->addWidget( mOption.portraitRadio, 0, AlignLeft );

  text = i18n("L&andscape");
  mOption.landscapeRadio = new QRadioButton( text, mOption.oriGroup );
  mOption.landscapeRadio->setFixedSize( mOption.landscapeRadio->sizeHint() );
  mOption.oriGroup->insert( mOption.landscapeRadio, 1 );
  vbox->addWidget( mOption.landscapeRadio, 0, AlignLeft );
  vbox->addStretch();

  mOption.colorGroup = new QButtonGroup( i18n("Colors"), page );
  if( mOption.colorGroup == 0 ) { return; }
  gbox->addWidget( mOption.colorGroup, 0, 1 );

  vbox = new QVBoxLayout( mOption.colorGroup, spacingHint() );  
  vbox->addSpacing( mOption.colorGroup->fontMetrics().height() );
  
  text = i18n("Print in c&olor");
  mOption.colorRadio = new QRadioButton( text, mOption.colorGroup );
  mOption.colorRadio->setFixedSize( mOption.colorRadio->sizeHint() );
  mOption.colorGroup->insert( mOption.colorRadio, 0 );
  vbox->addWidget( mOption.colorRadio, 0, AlignLeft );

  text = i18n("Print in &grayscale");
  mOption.grayRadio = new QRadioButton( text, mOption.colorGroup );
  mOption.grayRadio->setFixedSize( mOption.grayRadio->sizeHint() );
  mOption.colorGroup->insert( mOption.grayRadio, 1 );
  vbox->addWidget( mOption.grayRadio, 0, AlignLeft );

  text = i18n("Print in black and &white only");
  mOption.bwRadio = new QRadioButton( text, mOption.colorGroup );
  mOption.bwRadio->setFixedSize( mOption.bwRadio->sizeHint() );
  mOption.colorGroup->insert( mOption.bwRadio, 2 );
  vbox->addWidget( mOption.bwRadio, 0, AlignLeft );
  vbox->addStretch();
 
  //
  // Using a bit more space here. Looks better
  //
  topLayout->addSpacing( spacingHint());
  gbox = new QGridLayout( 4, 3, spacingHint()*2 );
  if( gbox == 0 ) { return; }
  topLayout->addLayout( gbox );
  gbox->setColStretch( 2, 10 );

  mOption.paperSelector = new QComboBox( false, page );
  mOption.paperSelector->setFixedHeight( 
    mOption.paperSelector->sizeHint().height() );
  mOption.paperSelector->setMinimumWidth( 
    mOption.paperSelector->fontMetrics().width("M")*10 );
  connect( mOption.paperSelector, SIGNAL(activated(int)), 
	   SLOT(paperTypeChanged(int)) );

  text = i18n("Paper t&ype");
  QLabel *paperLabel = new QLabel( mOption.paperSelector, text, page );
  paperLabel->setFixedHeight( mOption.paperSelector->sizeHint().height() );
  paperLabel->setMinimumWidth( paperLabel->sizeHint().width() );

  text = i18n("Size: 8888 x 8888 inches");
  mOption.paperSizeLabel = new QLabel( text, page );
  mOption.paperSizeLabel->setFixedHeight( 
    mOption.paperSelector->sizeHint().height() );
  mOption.paperSizeLabel->setMinimumWidth( 
    mOption.paperSizeLabel->sizeHint().width() );
  mOption.paperSizeLabel->hide();
 
  gbox->addWidget( paperLabel, 0, 0 );
  gbox->addWidget( mOption.paperSelector, 0, 1 );
  gbox->addWidget( mOption.paperSizeLabel, 0, 2 );


  text = i18n("&Scale down printed document to fit selected paper type");
  mOption.scaleCheck = new QCheckBox( text, page );
  if( mOption.scaleCheck == 0 ) { return; }
  mOption.scaleCheck->setFixedSize( mOption.scaleCheck->sizeHint() );
  gbox->addMultiCellWidget( mOption.scaleCheck, 1, 1, 0, 2, AlignLeft );


  mOption.pageSpin = new QSpinBox( page );
  mOption.pageSpin->setFixedHeight( mOption.pageSpin->sizeHint().height() );
  mOption.pageSpin->setMinimumWidth( 
    mOption.pageSpin->fontMetrics().width("M")*10 );
  mOption.pageSpin->setRange( 1, MAXINT );

  text = i18n("&Number of copies");
  QLabel *pageLabel = new QLabel( mOption.pageSpin, text, page );
  pageLabel->setFixedHeight( mOption.pageSpin->sizeHint().height() );
  pageLabel->setMinimumWidth( pageLabel->sizeHint().width() );
  
  gbox->addWidget( pageLabel, 2, 0 );
  gbox->addWidget( mOption.pageSpin, 2, 1 );
 
  QButtonGroup *group = new QButtonGroup( page );
  if( group == 0 ) { return; }
  group->setFrameStyle( QFrame::NoFrame );
  gbox->addMultiCellWidget( group,  3, 3, 0, 2, AlignLeft );


  QHBoxLayout *hbox = new QHBoxLayout( group, 0, spacingHint() );
  if( hbox == 0 ) { return; }

  text = i18n("Print &first page first");
  mOption.firstRadio = new QRadioButton( text, group );
  if( mOption.firstRadio == 0 ) { return; }
  mOption.firstRadio->setFixedSize( mOption.firstRadio->sizeHint() );
  group->insert( mOption.firstRadio, 0 );
  hbox->addWidget( mOption.firstRadio, 0, AlignLeft );

  text = i18n("Print &last page first");
  mOption.lastRadio = new QRadioButton( text, group );
  if( mOption.lastRadio == 0 ) { return; }
  mOption.lastRadio->setFixedSize( mOption.lastRadio->sizeHint() );
  group->insert( mOption.lastRadio, 0 );
  hbox->addWidget( mOption.lastRadio, 0, AlignLeft );

  hbox->addStretch(10);
 
  QFrame *hline = new QFrame( page );
  if( hline == 0 ) { return; }
  hline->setFrameStyle( QFrame::Sunken | QFrame::HLine );
  hline->setFixedHeight( hline->sizeHint().height() );
  topLayout->addWidget( hline );

  
  text = i18n("Pr&eview application");
  QLabel *previewLabel = new QLabel( text, page );
  if( previewLabel == 0 ) { return; }
  previewLabel->setFixedSize( previewLabel->sizeHint() );
  topLayout->addWidget( previewLabel, 0, AlignLeft );

  hbox = new QHBoxLayout();
  topLayout->addLayout( hbox );

  mOption.previewInput = new QLineEdit( page );
  //Fixed height, see below
  hbox->addWidget( mOption.previewInput, 10 );
  previewLabel->setBuddy( mOption.previewInput );

  text = i18n("Choose...");
  mOption.browseButton = new QPushButton( text, page, "browse" );
  mOption.browseButton->setAutoDefault( false );
  hbox->addWidget( mOption.browseButton );
  connect( mOption.browseButton, SIGNAL(clicked()),
	   SLOT(appBrowserClicked()) );
 

  QStringList list;
  paperType( list );
  mOption.paperSelector->insertStringList( list );  

  mOption.paperSelector->setCurrentItem( 0 );
  paperTypeChanged( 0 );

  mOption.portraitRadio->setChecked( true );
  mOption.colorRadio->setChecked( true );
  mOption.firstRadio->setChecked( true );
  mOption.scaleCheck->setChecked( true );
  mOption.previewInput->setText( QString("kghostview") );

  topLayout->addStretch(10);
}





void CPrinterDialog::setupLayoutPage( void )
{
  QString text;
  QFrame *page = mFrame[ page_layout ];

  QVBoxLayout *topLayout = new QVBoxLayout( page, 0, spacingHint() );  
  if( topLayout == 0 ) { return; }

  text = i18n("Margins [millimeter]");
  QButtonGroup *group = new QButtonGroup( text, page );
  if( group == 0 ) { return; }
  topLayout->addWidget( group );
 
  QGridLayout *gbox = new QGridLayout( group, 3, 6, spacingHint() );
  if( gbox == 0 ) { return; }
  gbox->addRowSpacing( 0, group->fontMetrics().height() );
  gbox->setColStretch( 5, 10 );
  
  QString name[4];
  int i;
  
  name[0] = i18n("&Top");
  name[1] = i18n("&Bottom");
  name[2] = i18n("&Left");
  name[3] = i18n("&Right");

  for( i=0; i<4; i++ )
  {
    mLayout.marginSpin[i] = new QSpinBox( group );
    mLayout.marginSpin[i]->setFixedHeight( 
      mLayout.marginSpin[i]->sizeHint().height() );
    mLayout.marginSpin[i]->setMinimumWidth( 
      mLayout.marginSpin[i]->fontMetrics().width("M")*10 );
    mLayout.marginSpin[i]->setRange( 0, MAXINT );

    QLabel *label = new QLabel( mLayout.marginSpin[i], name[i], group );
    label->setFixedHeight( mLayout.marginSpin[i]->sizeHint().height() );
    label->setFixedWidth( label->sizeHint().width() );

    if( i < 2 )
    {
      gbox->addWidget( label, i+1, 0, AlignLeft );
      gbox->addWidget( mLayout.marginSpin[i], i+1, 1, AlignLeft );
    }
    else
    {
      gbox->addWidget( label, i-1, 3, AlignLeft );
      gbox->addWidget( mLayout.marginSpin[i], i-1, 4, AlignLeft );
    }
  }
  
  text = i18n("Draw h&eader above text");
  mLayout.headerCheck = new QCheckBox( text, page );
  mLayout.headerCheck->setFixedSize( mLayout.headerCheck->sizeHint() );
  connect( mLayout.headerCheck, SIGNAL( toggled(bool)),
	   SLOT( slotDrawHeader(bool)));
  topLayout->addWidget( mLayout.headerCheck, 0, AlignLeft );

  gbox = new QGridLayout( 5, 6, 0 );
  if( gbox == 0 ) { return; }
  topLayout->addLayout( gbox );

  gbox->setColStretch ( 5, 10 );
  gbox->addColSpacing( 1, spacingHint() );
  gbox->addColSpacing( 3, spacingHint() );
  gbox->addRowSpacing( 2, spacingHint() );
  
  name[0] = i18n("Left");
  name[1] = i18n("Center");
  name[2] = i18n("Right");
  name[3] = i18n("Border");

  QStringList textList;
  textList.append(i18n("None"));
  textList.append(i18n("Date and time"));
  textList.append(i18n("Page number"));
  textList.append(i18n("Filename"));

  QStringList lineList;
  lineList.append(i18n("None"));
  lineList.append(i18n("Single line"));
  lineList.append(i18n("Rectangle"));

  for( i=0; i<4; i++ )
  {
    mLayout.headerCombo[i] = new QComboBox( false, page );
    mLayout.headerCombo[i]->setFixedHeight( 
      mLayout.headerCombo[i]->sizeHint().height() );
    mLayout.headerCombo[i]->setMinimumWidth( 
      mLayout.headerCombo[i]->fontMetrics().width("M")*10 );
 
    mLayout.headerLabel[i] = new QLabel( mLayout.headerCombo[i], name[i], 
					 page );
    mLayout.headerLabel[i]->setFixedHeight( 
      mLayout.headerLabel[i]->sizeHint().height() );
    mLayout.headerLabel[i]->setFixedWidth( 
      mLayout.headerLabel[i]->sizeHint().width() );

    if( i<3 )
    {
      mLayout.headerCombo[i]->insertStringList( textList );
      gbox->addWidget( mLayout.headerLabel[i], 0, i*2, AlignLeft );
      gbox->addWidget( mLayout.headerCombo[i], 1, i*2, AlignLeft );
    }
    else
    {
      mLayout.headerCombo[i]->insertStringList( lineList );
      gbox->addWidget( mLayout.headerLabel[i], 3, 0, AlignLeft );
      gbox->addWidget( mLayout.headerCombo[i], 4, 0, AlignLeft );
    }
  }


  text = i18n("Draw &footer below text");
  mLayout.footerCheck = new QCheckBox( text, page );
  mLayout.footerCheck->setFixedSize( mLayout.footerCheck->sizeHint() );
  connect( mLayout.footerCheck, SIGNAL( toggled(bool)),
	   SLOT( slotDrawFooter(bool)));
  topLayout->addWidget( mLayout.footerCheck, 0, AlignLeft );

  gbox = new QGridLayout( 5, 6, 0 );
  if( gbox == 0 ) { return; }
  topLayout->addLayout( gbox );

  gbox->setColStretch ( 5, 10 );
  gbox->addColSpacing( 1, spacingHint() );
  gbox->addColSpacing( 3, spacingHint() );
  gbox->addRowSpacing( 2, spacingHint() );

  for( i=0; i<4; i++ )
  {
    mLayout.footerCombo[i] = new QComboBox( false, page );
    mLayout.footerCombo[i]->setFixedHeight( 
      mLayout.footerCombo[i]->sizeHint().height() );
    mLayout.footerCombo[i]->setMinimumWidth( 
      mLayout.footerCombo[i]->fontMetrics().width("M")*10 );

    mLayout.footerLabel[i] = new QLabel( mLayout.footerCombo[i], name[i], 
					 page );
    mLayout.footerLabel[i]->setFixedHeight( 
      mLayout.footerLabel[i]->sizeHint().height() );
    mLayout.footerLabel[i]->setFixedWidth( 
      mLayout.footerLabel[i]->sizeHint().width() );

    if( i<3 )
    {
      mLayout.footerCombo[i]->insertStringList( textList );
      gbox->addWidget( mLayout.footerLabel[i], 0, i*2, AlignLeft );
      gbox->addWidget( mLayout.footerCombo[i], 1, i*2, AlignLeft );
    }
    else
    {
      mLayout.footerCombo[i]->insertStringList( lineList );
      gbox->addWidget( mLayout.footerLabel[i], 3, 0, AlignLeft );
      gbox->addWidget( mLayout.footerCombo[i], 4, 0, AlignLeft );
    }
  }

  for( i=0; i<4; i++ )
  {
    mLayout.marginSpin[i]->setValue( 15 );
  }
  mLayout.headerCheck->setChecked( true );
  slotDrawHeader( true );
  mLayout.footerCheck->setChecked( true );
  slotDrawFooter( true );

  topLayout->addStretch(10);
}




void CPrinterDialog::printFileCheck( void )
{
  bool state = mDestination.fileCheck->isChecked();
  mDestination.fileInput->setEnabled( state );
  mDestination.browseButton->setEnabled( state );
  state = state == true ? false : true;
  mDestination.printerLabel->setEnabled( state );
  mDestination.printerList->setEnabled( state );
}

void CPrinterDialog::browserClicked( void )
{
  KURL file = KFileDialog::getSaveURL( mWorkDir, "*", topLevelWidget());
  
  if( file.isEmpty() )
    return;

  if( !file.isLocalFile() )
  {
    KMessageBox::sorry( 0L, i18n( "Only local files are currently supported." ) );
    return;
  }

  QString url = file.path();

  int index = url.findRev( '/' );
  if( index != -1 ) { mWorkDir = url.left( index+1 ); }
  mDestination.fileInput->setText( url );
}


void CPrinterDialog::appBrowserClicked( void )
{
  KURL file = KFileDialog::getOpenURL( mAppDir, "*", topLevelWidget() );
  
  if( file.isEmpty() )
    return;
  
  if( !file.isLocalFile() )
  {
    KMessageBox::sorry( 0L, i18n( "Only local files are currently supported." ) );
    return;
  }
  
  QString url = file.path();
  int index = url.findRev( '/' );
  if( index != -1 ) { mAppDir = url.left( index+1 ); }
  mOption.browseButton->setText( url );
}


void CPrinterDialog::printRangeClicked( int id )
{
  bool state = id == 2 ? true : false;
  mDestination.toLabel->setEnabled( state );
  mDestination.fromLabel->setEnabled( state );
  mDestination.toInput->setEnabled( state );
  mDestination.fromInput->setEnabled( state );
}

void CPrinterDialog::textFormatClicked( int id )
{
  mDestination.helpLabel->setEnabled( id == 1 ? true : false );
}


void CPrinterDialog::paperTypeChanged( int id )
{
  const SPageSize &size = paperSize( (KPrinter::PageSize)id );
  QString msg;
  
  if( size.isInch == true )
  {
    msg = i18n("Size: %1 x %2 inches")
      .arg(KGlobal::locale()->formatNumber(size.width, 1))
      .arg(KGlobal::locale()->formatNumber(size.height, 1));
  }
  else
  {
    msg = i18n("Size: %1 x %2 mm")
      .arg(KGlobal::locale()->formatNumber(size.width, 0))
      .arg(KGlobal::locale()->formatNumber(size.height, 0));
  }

  mOption.paperSizeLabel->setText( msg ); 
  mOption.paperSizeLabel->show();
}



void CPrinterDialog::slotDrawHeader( bool state )
{
  for( int i=0; i<4; i++ )
  {
    mLayout.headerLabel[i]->setEnabled( state );
    mLayout.headerCombo[i]->setEnabled( state );
  }
}


void CPrinterDialog::slotDrawFooter( bool state )
{
  for( int i=0; i<4; i++ )
  {
    mLayout.footerLabel[i]->setEnabled( state );
    mLayout.footerCombo[i]->setEnabled( state );
  }
}


void CPrinterDialog::slotUser1( void ) // Print
{
  mPrinter.setOutputToStdout( false );
  mPrinter.setAsText( mDestination.textRadio->isChecked() );

  if( mDestination.fileCheck->isChecked() == true )
  {
    QString path( mDestination.fileInput->text() );

    if( verifyFileDestnation( this, i18n("Print"), path ) == false )
    {
      return;
    }

    mPrinter.setOutputToFile( true );
    mPrinter.setOutputFileName( path );
  }
  else
  {
    QListViewItem *listItem = mDestination.printerList->currentItem();
    if( listItem == 0 )
    {
      QString msg = i18n("You have not selected a printer.");
      KMessageBox::sorry( this, msg, i18n("Print") );
      return;
    }

    mPrinter.setOutputToFile( false );
    mPrinter.setPrinterName( listItem->text( 0 ) );
  }

  if( mOption.portraitRadio->isChecked() == true )
  {
    mPrinter.setOrientation( KPrinter::Portrait );
  }
  else
  {
    mPrinter.setOrientation( KPrinter::Landscape );
  }

  mPrinter.setPageSize( 
    (KPrinter::PageSize)mOption.paperSelector->currentItem() );
  mPrinter.setFullPage( true ); // I use my own marings
  
  if( mOption.firstRadio->isChecked() == true )
  {
    mPrinter.setPageOrder( KPrinter::FirstPageFirst );
  }
  else
  {
    mPrinter.setPageOrder( KPrinter::LastPageFirst );
  }

  mPrinter.setNumCopies( mOption.pageSpin->value() );
  mPrinter.setScaleToFit( mOption.scaleCheck->isChecked() );

  mPrinter.setTopMarginMM( mLayout.marginSpin[0]->value() );
  mPrinter.setBottomMarginMM( mLayout.marginSpin[1]->value() );
  mPrinter.setLeftMarginMM( mLayout.marginSpin[2]->value() );
  mPrinter.setRightMarginMM( mLayout.marginSpin[3]->value() );

  mPrinter.setPageHeader( mLayout.headerCheck->isChecked(),
			  mLayout.headerCombo[0]->currentItem(),
			  mLayout.headerCombo[1]->currentItem(),
			  mLayout.headerCombo[2]->currentItem(),
			  mLayout.headerCombo[3]->currentItem() );

  mPrinter.setPageFooter( mLayout.footerCheck->isChecked(),
			  mLayout.footerCombo[0]->currentItem(),
			  mLayout.footerCombo[1]->currentItem(),
			  mLayout.footerCombo[2]->currentItem(),
			  mLayout.footerCombo[3]->currentItem() );

  if( mOption.colorRadio->isChecked() == true )
  {
    mPrinter.setColorMode( KPrinter::Color );
    mPrinter.setPrintBackWhite( false );
  }
  else if( mOption.grayRadio->isChecked() == true )
  {
    mPrinter.setColorMode( KPrinter::GrayScale );
    mPrinter.setPrintBackWhite( false );
  }
  else
  {
    mPrinter.setColorMode( KPrinter::Color );
    mPrinter.setPrintBackWhite( true );
  }

  if( mDestination.allRadio->isChecked() == true )
  {
    mPrinter.setAll( true );
    mPrinter.setSelection( false );
    mPrinter.setRange( false );
    mPrinter.setFromTo( mPrinter.minPage(), mPrinter.maxPage() );
  }
  else if( mDestination.selectRadio->isChecked() == true )
  {
    mPrinter.setAll( false );
    mPrinter.setSelection( true );
    mPrinter.setRange( false );
  }
  else
  {
    uint start, stop;
    bool ok1 = stringToOffset( mDestination.fromInput->text(), start );
    bool ok2 = stringToOffset( mDestination.toInput->text(), stop );

    if( ok1 == false || ok2 == false || start >= stop )
    {
      QString msg = i18n("Illegal format or missing range specification");
      KMessageBox::sorry( this, msg, i18n("Print") );
      return;
    }

    mPrinter.setAll( false );
    mPrinter.setSelection( false );
    mPrinter.setRange( true, start, stop );
  }



  if( mDestination.textRadio->isChecked() == true )
  {
    if( mPrinter.outputToFile() == false )
    {
      QString msg = i18n(""
        "Not available yet!\n"
	"Print plain text to printer" );
      KMessageBox::sorry( this, msg, i18n("Print") );
      return;
    }
  }

  hide();
  if( mDestination.textRadio->isChecked() == true )
  {
    printText( mPrinter );
  }
  else
  {
    printPostscript( mPrinter );
  }

}



void CPrinterDialog::slotUser2( void ) // Preview
{
  QString msg = i18n(""
    "Not available yet!\n"
    "Print preview" );
  KMessageBox::sorry( this, msg, i18n("Print") );
}







bool CPrinterDialog::parsePrintcap( void )
{
  bool emptyPrintcap, noPrintcap;
  QString tmp, name;

  const char *path[] =
  { 
    "/etc/printers.conf", 
    "/etc/printcap", 
    "/usr/local/etc/printcap",
    0
  };

  emptyPrintcap = noPrintcap = TRUE;

  for( uint i=0; path[i] != 0; i++ )
  {
    QFile file( path[i] );
    if( file.open( IO_ReadOnly ) == FALSE )
    {
      continue;
    }

    noPrintcap = FALSE;

    QTextStream st( (QIODevice *)&file );
    while( st.eof() == FALSE )
    {
      tmp = st.readLine();
      tmp = tmp.stripWhiteSpace();
      if( tmp[0] == '#' || tmp.isEmpty() )
      {
	continue;
      }
      name = tmp.left( tmp.find(':') );
      if( name.isEmpty() )
      {
	continue;
      }
      if( name.contains('|') )
      {
	name = name.left( name.find('|') );
      }
      name = name.stripWhiteSpace();
      if( name.isEmpty() )
      {
	continue;
      }
      else
      {
	emptyPrintcap = FALSE;
      }

      addPrinterName( name );
    }

    file.close();
  }

  setSelectedPrinter( QString() ); // Select the first

  return( emptyPrintcap == TRUE ? FALSE : TRUE );
}

void CPrinterDialog::addPrinterName( const QString &printer )
{
  const QListViewItem *entry = mDestination.printerList->firstChild();
  for( ; entry != 0; entry = entry->nextSibling() )
  {
    if( entry->text(0) == printer )
    {
      return;
    }
  }
  
  (void)new QListViewItem( mDestination.printerList, printer, "", "" );

}


void CPrinterDialog::setSelectedPrinter( const QString &name )
{
  QListViewItem *entry = mDestination.printerList->firstChild();
  for( ; entry != 0; entry = entry->nextSibling() )
  {
    if( entry->text(0) == name )
    {
      mDestination.printerList->setSelected ( entry, true );
      return;
    }
  }

  //
  // Use the first
  //
  entry = mDestination.printerList->firstChild();
  if( entry != 0 )
  {
    mDestination.printerList->setSelected ( entry, true );
  }
}



void CPrinterDialog::timerEvent( QTimerEvent * )
{
  killTimers();
  QString msg = i18n("Unable to parse or read any printcap files" );
  KMessageBox::sorry( this, msg, i18n("Print") );
}




void CPrinterDialog::paperType( QStringList &list )
{
  list.append(i18n("A4"));
  list.append(i18n("B5"));
  list.append(i18n("Letter"));
  list.append(i18n("Legal"));
  list.append(i18n("Executive"));
  #if 0
  list.append(i18n("A0"));
  list.append(i18n("A1"));
  list.append(i18n("A2"));
  list.append(i18n("A3"));
  list.append(i18n("A5"));
  list.append(i18n("A6"));
  list.append(i18n("A7"));
  list.append(i18n("A8"));
  list.append(i18n("A9"));
  list.append(i18n("B0"));
  list.append(i18n("B1"));
  list.append(i18n("B10"));
  list.append(i18n("B2"));
  list.append(i18n("B3"));
  list.append(i18n("B4"));
  list.append(i18n("B6"));
  list.append(i18n("B7"));
  list.append(i18n("B8"));
  list.append(i18n("B9"));
  list.append(i18n("C5E"));
  list.append(i18n("Comm10E"));
  list.append(i18n("DLE"));
  list.append(i18n("Folio"));
  list.append(i18n("Ledger"));
  list.append(i18n("Tabloid"));
  #endif
}



const CPrinterDialog::SPageSize CPrinterDialog::paperSize( 
			        KPrinter::PageSize pageSize )
{

  KPrinter printer;
  printer.setPageSize( pageSize );
  printer.setFullPage( true ); // I use my own margins

  QPaintDeviceMetrics paintMetric( &printer );
  SPageSize size;

  if( pageSize == KPrinter::Executive || pageSize == KPrinter::Legal ||
      pageSize == KPrinter::Letter )
  {
    size.width  = (double)paintMetric.widthMM() / 25.4;
    size.height = (double)paintMetric.heightMM() / 25.4;
    size.isInch = true;
  }
  else
  {
    size.width  = (double)paintMetric.widthMM();
    size.height = (double)paintMetric.heightMM();
    size.isInch = false;
  }
  return( size );

  #if 0
  static SPageSize size[ KPrinter::Tabloid+2 ] = 
  {
    {210,  297},  // A4
    {182,  257},  // B5
    {216,  279},  // Letter
    {216,  356},  // Legal
    {191,  254},  // Executive
    {841,  1189}, // A0  
    {594,  841},  // A1
    {420,  594},  // A2
    {297,  420},  // A3
    {148,  210},  // A5
    {105,  148},  // A6
    {74,   105},  // A7
    {52,   74},   // A8
    {37,   52},   // A9
    {1030, 1456}, // B0 
    {728,  1030}, // B1
    {32,   45},   // B10
    {515,  728},  // B2
    {364,  515},  // B3
    {257,  364},  // B4
    {128,  182},  // B6
    {91,   128},  // B7
    {64,   91},   // B8
    {45,   64},   // B9
    {163,  229},  // C5E
    {105,  241},  // Comm10E
    {110,  220},  // DLE
    {210,  330},  // Folio
    {432,  279},  // Ledger
    {279,  432},  // Tabloid 
    {0,    0},    // Unknown
  };

  return( size[ pageSize > KPrinter::Tabloid ? KPrinter::Tabloid : pageSize ]);
  #endif
}
#include "printerdialog.moc"
