/****************************************************************************
**
** Copyright (C) 2000 by Daniel Duley <mosfet@kde.org>, David Sweet <dsweet@kde.org>
** Copyright (C) 1997 by Mark Donohoe.
** Based on original work by Tim Theisen.
**
** This code is freely distributable under the GNU Public License.
**
*****************************************************************************/

/**
 * This is essentially the KGhostview widget stripped down and without all the
 * KTMainWindow dependencies (there were quite a bit with menus, toolbars,
 * etc.. accessed all over the place). It would probably make sense to make
 * that use this in the future (ported by mosfet@kde.org).
 */

#include <assert.h>
#include <unistd.h>

#include <qdragobject.h>
#include <qlistbox.h>
#include <qlayout.h>
#include <qpaintdevicemetrics.h>

#include <kapp.h>
#include <kconfig.h>
#include <kfiledialog.h>
#include <ktempfile.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kmimemagic.h>
#include <kio/netaccess.h>
#include <knotifyclient.h>
#include <kdebug.h>
#include <kinstance.h>
#include <kgv_view.h>

#include <config.h>

#include "gotodialog.h"
#include "infodialog.h"
#include "kgv_miniwidget.h"
#include "printdialog.h"
extern "C" {
#include "ps.h"
}
#include "version.h"


#ifdef HAVE_PATHS_H
#include <paths.h>
#endif

#ifndef _PATH_TMP
#define _PATH_TMP "/tmp/"
#endif

#include "kgv_miniwidget.moc"


KGVMiniWidget::KGVMiniWidget( KPSWidget* psWidget, KGVPart* parent,
			      const char* )
 : QWidget( /*parent, name*/ )
 , _useManualOrientation( false )
 , _manualOrientation( 0 )
 , _useManualPageMedia( false )
 , _manualPageMedia( 0 )
 , _defaultPageMedia( 1 )
{   
    // Initialise all the variables declared in this class.
    // I ususally forget to do a few resulting in nasty seg. faults !
  
    _fileName = "";
    psfile=0;
    _doc = 0;
    doc=0;
    mGotoDialog=0;
    _useFancyPageLabels = false;

    current_page=0;
    shrink_magsteps = 10;
    expand_magsteps = 10;
    _magstep = 10;
    base_papersize=0;
  
    page = psWidget;
    _marklist = parent->markList();

    // Get the screen resolution.
    QPaintDeviceMetrics qpdm( page );
    _defaultXdpi = qpdm.logicalDpiX();
    _defaultYdpi = qpdm.logicalDpiY();
  
    readSettings();
}

KGVMiniWidget::~KGVMiniWidget()
{
    if( mGotoDialog != 0 )
	delete mGotoDialog;
    if (!tmpfile1.isEmpty())
	unlink (QFile::encodeName(tmpfile1));
    if (!tmppdf.isEmpty())
	unlink (QFile::encodeName(tmppdf));
}

void
KGVMiniWidget::info()
{
    QString ftitle, fdate;
    if( _doc ) {
	ftitle = _doc->title();
	fdate = _doc->date();
    } 
    else {
	ftitle = i18n("Not known");
	fdate = ftitle;
    }
  
    mInfoDialog = new InfoDialog( topLevelWidget(), "info", true );
    mInfoDialog->setup( _fileName, ftitle, fdate );
    mInfoDialog->exec();
    delete mInfoDialog;
}

void
KGVMiniWidget::configureGhostscript()
{
    if( page->configure() )
	redisplay();
}

void
KGVMiniWidget::readSettings()
{
    // Don't set the group here.
    KConfig *config = KGVFactory::instance()->config();

    _interpreterPath = config->readEntry( "Interpreter", "gs" );
    _useFancyPageLabels = config->readBoolEntry( "FancyPageLabels", false );

    int i = config->readNumEntry( "Magstep", 10 );
    if( i < 20 && i > 0 )
	_magstep = i;
  
    setMagstep( i );
}

void
KGVMiniWidget::paletteChange( const QPalette & )
{
    _marklist->setSelectColors( colorGroup().highlight(), 
				colorGroup().highlightedText() );
    redisplay();
}

void
KGVMiniWidget::markPage()
{
    _marklist->markSelected();
}


void
KGVMiniWidget::goToPage()
{
    /*
  //printf ("goToPage()\n");
  if (mGotoDialog==0)
    {
      mGotoDialog = new GotoDialog( this, "goto", false );
      connect( mGotoDialog, SIGNAL(gotoPage(int)), this, SLOT(goToPage(int)) );
    }
  
  mGotoDialog->setup(GotoDialogData(current_page+1,
				    num_parts+1, pages_in_part));
  mGotoDialog->show();
  */

}


void KGVMiniWidget::goToPage( int page )
{
    if( current_page != page ) {
	current_page = page;
	show_page( page );
    }
}

void KGVMiniWidget::print()
{
    PrintDialog* pd = new PrintDialog( this, "print dialog", i18n( "Print" ), 
		    _doc->numberOfPages(), !_marklist->markList().isEmpty() );
  
    if( pd->exec() ) {
	QValueList<int> pagelist;
	QString error;
    
	pagelist = generatePageList( pd->pageMode(), pd->reverseOrder(),
				     pd->from(), pd->to(), pd->copies() );
	
	if( pd->printToFile() )
	    error = printToFile( pagelist, pd->saveURL() );
	else
	    error = printToPrinter( pagelist, false );
    }

    delete pd;
}

void KGVMiniWidget::zoomIn()
{
    unsigned int i;
  
    i = _magstep + 1;
    if( i <= shrink_magsteps + expand_magsteps )
	setMagstep(i);
}

void KGVMiniWidget::zoomOut()
{
    int i;
  
    i = _magstep - 1;
    if( i >= 1 )
	setMagstep( (unsigned int)i );
}

void KGVMiniWidget::firstPage()
{
    goToPage( 0 );
}

void KGVMiniWidget::lastPage()
{
    goToPage( _doc->numberOfPages() - 1 );
}

void KGVMiniWidget::prevPage()
{
    int new_page = 0;
  
    if( toc_text ) {
	new_page = current_page - 1;
	if( new_page < 0 )
	    return;
    }
    
    goToPage( new_page );
}

void KGVMiniWidget::nextPage()
{
    int new_page = 0;
  
    if( toc_text ) {
	new_page = current_page + 1;
	if( (unsigned int)new_page >= _doc->numberOfPages() )
	    return;
    }
  
    goToPage( new_page );
}

QValueList<int> KGVMiniWidget::generatePageList( 
				    int mode, bool reverseOrder, 
				    int pgStart, int pgEnd,
				    unsigned int copies )
{
    QValueList<int> pagelist;
 
    switch( mode ) {
    
    case PrintDialog::All:
	for( unsigned int j = 1; j <= _doc->numberOfPages(); j++ )
	    pagelist.append( j );
	break;
      
    case PrintDialog::Current:
	pagelist.append( current_page + 1 );
	break;
      
    case PrintDialog::Marked:
	pagelist = _marklist->markList();
	break;
      
    case PrintDialog::Range:
	if ( pgStart <= pgEnd )
	    for( int j = pgStart; j <= pgEnd; j++ )
		pagelist.append( j );
	else 
	    for( int j = pgEnd; j <= pgStart; j++ )
		pagelist.append( j );
	    break;
    }
	
    if( reverseOrder ) {
	QValueList<int> sl;
	QValueList<int>::Iterator it;
	for( it = pagelist.fromLast(); it != pagelist.end(); --it )
	    sl.append( *it );
	pagelist = sl;
    }

    if( copies > 1 ) {
	QValueList<int> copy = pagelist;
	for( unsigned j = 1; j < copies; ++j )
	    pagelist += copy;
    }

    return pagelist;
}

void KGVMiniWidget::saveAs()
{
  // printToFile();
}

QString KGVMiniWidget::printToFile( const QValueList<int>& pagelist, 
				    const QString& saveURL )
{
    FILE* pswrite;
  
    QString usefile;
    if( format==PDF ) {
	if( convertFromPDF() )
	    usefile = tmppdf;
	else
	    return i18n("Could not convert file from PDF to PS format.");
    }
    else
	usefile = _fileName;

    QString dir;
    if( origurl.isLocalFile() )
	dir = origurl.directory();
    
    //else use CWD
    //  if ( usefile )	dir = QFileInfo( usefile ).dirPath();
  
  /*
    KURL saveurl = KFileDialog::getSaveURL( dir,
				    "*.ps|Postscript files (*.ps)");
  */

    kdDebug(4500) << "Saving to: " << saveURL << endl;
    KURL saveurl( saveURL );

  //TODO
  //		"\n*.eps|Encapsulated Postscript files (*.eps)"
  //	"\n*.pdf|Portable Document Format files (*.pdf)" );
  
  
  //  KURL saveurl ("file:/home/dsweet/1.ps");
  //printf ("SAVETO [%s]\n", (const char*)saveurl.url());

  //TODO -- save as PDF!

    if( saveurl.isEmpty() ) {
	return QString::null; //user cancelled, no error
    }
  
    QString s;

    if( !saveurl.isLocalFile() )
	s = kapp->tempSaveName( saveurl.fileName() );
    else
	s = saveurl.path();

    //printf ("SAVETO/s [%s]\n", (const char*)s);

    if( ( pswrite = fopen( QFile::encodeName(s), "w" ) ) == 0L ) {
	QString buf;
	buf = i18n( "Attempt to open file for writing failed.\n\n"
		    "Error: %1\n")
		    .arg( strerror(errno) );
	return buf;
    }
    else {
	psCopyDoc( pswrite, pagelist );
	fclose( pswrite );
	if( !saveurl.isLocalFile() ) {
	    if( !KIO::NetAccess::upload( s, saveurl ) )
		return QString( i18n( "Could not transfer file to URL %1.")
				      .arg (saveurl.url()));
	}
	return QString::null;
    }
}

QString KGVMiniWidget::printToPrinter( const QValueList<int>& pagelist, 
				       bool allMode )
{
    FILE* printer;
    SIGVAL (*oldsig) (int);
    int bytes = 0;
    char buf[ BUFSIZ ];
    bool failed;
    QString ret_val;
  
    page->disableInterpreter();
  
  // For SYSV, SVR4, USG printer variable="LPDEST", print command=lp
  // Other systems printer variable="PRINTER", print command=lpr
  
  // Why add double quotes ? It breaks setenv... David Faure.
  // printerVariable.append("\"");
  // printerVariable.prepend("\"");
  
    // Read the printer configuration
    KConfig* config = KGVFactory::instance()->config();
    config->setGroup( "Print" );

    QString printerName = config->readEntry( "Name" );
    QString spoolerCommand = config->readEntry( "Spool", "lpr" );
    QString printerVariable = config->readEntry( "Variable", "PRINTER" );
    
    if( !printerName.isEmpty() ) {
	if( !printerVariable.isEmpty() ) {
	    setenv( QFile::encodeName(printerVariable), 
		    QFile::encodeName(printerName), true );
	}
	else
	    return i18n( 
	"If you want the name of the printer to be used, you must set either "
	"PRINTER or LPDEST in your environment." );
    }

    // TODO -- kprocess again (keep UI alive!)
    QString usefile;
    if( format == PDF ) {
	if( convertFromPDF() )
	    usefile = tmppdf;
	else
	    return i18n( "Could not convert file from PDF to PS format." );
    }
    else
	usefile = _fileName;


    oldsig = signal( SIGPIPE, SIG_IGN );
    printer = popen( QFile::encodeName(spoolerCommand), "w" );
  
    if ( toc_text && !allMode ) {
	psCopyDoc( printer, pagelist );
    } 
    else {
	FILE *tmpfile = ::fopen( QFile::encodeName( _fileName ), "r" );
      
	while ( ( bytes = ::read( fileno(tmpfile), buf, BUFSIZ ) ) ) {
	    bytes = ::write( fileno(printer), buf, bytes);
	}
	::fclose( tmpfile );
    }
	
    failed = ( pclose( printer ) != 0 );
  
    ret_val = failed?i18n("Print failure: %1").arg(spoolerCommand):QString::null;
	
    signal( SIGPIPE, oldsig );
    return( ret_val );
}


// length calculates string length at compile time
// can only be used with character constants

#define length( a ) ( sizeof( a ) - 1 )

// Copy the headers, marked pages, and trailer to fp

void
KGVMiniWidget::psCopyDoc( FILE *fp, const QValueList<int>& pagelist )
{
  
  FILE *psfile;
  char text[ PSLINELENGTH ];
  char *comment;
  bool pages_written = false;
  bool pages_atend = false;
  int pages = 0;
  int page = 1;
  unsigned int i;
  long here;
  
  psfile = fopen( QFile::encodeName( _fileName), "r" );
  
    pages = pagelist.count();
    //TODO -- KNotifyClient
    if( pages == 0 ) {
	KMessageBox::error( 0,
			  i18n( "Printing failed because the list of\n"
				"pages to be printed was empty.\n" ),
			  i18n( "Error printing" ));
	return;
    }
  
  here = doc->beginheader;
  while ( ( comment = 
	    pscopyuntil( psfile, fp, here,
			 doc->endheader, "%%Pages:" ) ) ) 
    {
      here = ftell( psfile );
      if ( pages_written || pages_atend ) 
	{
	  free( comment );
	  continue;
	}
      sscanf( comment + length("%%Pages:" ), "%s", text );
      if ( strcmp( text, "(atend)" ) == 0 ) 
	{
	  fputs( comment, fp );
	  pages_atend = true;
	} 
      else
	{
	  switch ( sscanf( comment + length( "%%Pages:" ), "%*d %d", &i ) ) 
	    {
	    case 1:
	      fprintf( fp, "%%%%Pages: %d %d\n", pages, i );
	      break;
	    default:
	      fprintf( fp, "%%%%Pages: %d\n", pages );
	      break;
	    }
	  pages_written = true;
	}
      free(comment);
    }
    pscopy( psfile, fp, doc->beginpreview, doc->endpreview );
    pscopy( psfile, fp, doc->begindefaults, doc->enddefaults );
    pscopy( psfile, fp, doc->beginprolog, doc->endprolog );
    pscopy( psfile, fp, doc->beginsetup, doc->endsetup );
  
    //TODO -- Check that a all doc attibutes are copied
    //TODO -- fix gz and pdf copying

    QValueList<int>::ConstIterator it;
    for( it = pagelist.begin(); it != pagelist.end(); ++it ) {
	i = (*it) - 1;
      
	comment = pscopyuntil( psfile, fp, doc->pages[i].begin,
			     doc->pages[i].end, "%%Page:" );
      
      fprintf( fp, "%%%%Page: %s %d\n",
	       doc->pages[i].label, page++ );
      
      free( comment );
      pscopy( psfile, fp, -1, doc->pages[i].end );
    }
  
  here = doc->begintrailer;
  while ( ( comment = pscopyuntil(psfile, fp, here,
				  doc->endtrailer, "%%Pages:" ) ) ) 
    {
      here = ftell( psfile );
      if ( pages_written ) 
	{
	  free( comment );
	  continue;
	}
      switch ( sscanf( comment + length( "%%Pages:" ), "%*d %d", &i ) ) 
	{
	case 1:
	  fprintf( fp, "%%%%Pages: %d %d\n", pages, i );
	  break;
	default:
	  fprintf( fp, "%%%%Pages: %d\n", pages );
	  break;
	}
      pages_written = true;
      free( comment );
    }
  fclose( psfile );
}

#undef length

bool KGVMiniWidget::openFile( QString name )
{
    kapp->processEvents();

    page->enableInterpreter();

    if ( !tmpfile1.isEmpty() )
	QFile::remove( tmpfile1 );
  
    // Write the stdin input to a temporary file if necessary.
    if( name == QString::fromLatin1( "-" ) ) {
	KTempFile* tf = new KTempFile;

	const int BuffSize = 2048;
	int e;
	char *buff = new char [BuffSize];
	while ( ( e = fread( buff, sizeof(char), BuffSize, stdin ) ) > 0 )
	    fwrite( buff, sizeof(char), e, tf->fstream() );
	delete buff;
	
	name = tf->name();
	delete tf;

	if( e < 0 ) {
	    KNotifyClient::userEvent( 
		    i18n( "Open of standard input stream failed: " ) 
		    + strerror(errno));
	    return false;
	}
    }

    //TODO -- Use KProcess instead of system!

    if( !QFile::exists( name ) ) {
	kdError(4500) << "cannot open " << name << endl;
	KNotifyClient::userEvent( i18n( "Cannot open file" ) + name, 
		KNotifyClient::Messagebox);
	return false;
    }

    QString mimetype( KMimeMagic::self()->findFileType( name )->mimeType() );
   
    // First check if the file is compressed and uncompress it.
    if( mimetype == "application/x-gzip" ) {
	const char *cmd_uncompress = "gzip -d -c %s > %s";
	QCString cmd;
	char filename_unc [1024];
	sprintf( filename_unc, "%s/kgvtmp_ungz_%d",
		_PATH_TMP, getpid());
	cmd.sprintf( cmd_uncompress, QFile::encodeName(name).data(), 
		filename_unc);

	tmpfile1 = filename_unc;
	int r = system( cmd );
	
	if( r == 0 ) {
	    name = filename_unc;
	    mimetype = KMimeMagic::self()->findFileType( name )->mimeType();
	}
	else {
	    QString er =
		    i18n("Error opening file, \"%1\": %2")
		    .arg( name ).arg( strerror( errno ) );
	    KNotifyClient::userEvent( er, KNotifyClient::Messagebox );
	    return false;
	}
    }
    
    if( mimetype == "application/postscript" )
	format = PS;
    else if (mimetype == "application/pdf")
	format = PDF;
    else {
	kdError(4500) << "mimetype = " << mimetype << endl;
	KNotifyClient::userEvent( i18n(
		"KGhostview can only load Postscript (.ps, .eps), \n"
		"and Portable Document Format (.pdf) files." ),
		KNotifyClient::Messagebox);
	return false;
    }
   
    FILE* fp;
    
    if( ( fp = fopen( QFile::encodeName( name ), "r") ) == 0 ) {
	QString er =
		i18n("Error opening file, \"%1\": %2")
		.arg (name).arg(strerror(errno));
	KNotifyClient::userEvent( er, KNotifyClient::Messagebox );
	return false;
    } 
    else {
	_fileName = name;
	if( psfile ) 
	    fclose( psfile );
	  
	psfile = fp;

	new_file( 0 );
	if( !_doc )
	    return false;
    
	//When all else fails...use a hack :(
	int w=page->width(), h=page->height();
	page->resize (w-1,h-1);
	page->resize (w,h);
	return true;
    }
}

void KGVMiniWidget::fileChanged( const QString& name )
{
    if( !psfile )
	return;

    unsigned int savepage = current_page;
 
    if( openFile( name ) ) 
	goToPage( savepage );
    else 
	emit fileChangeFailed();
}

void KGVMiniWidget::redisplay ()
{
    if( !psfile )
	return;

    page->disableInterpreter();
    show_page( current_page );
}

int KGVMiniWidget::guessOrientation( int pagenumber ) const
{
    if( !_doc->isEPSF() )
	return PORTRAIT;
    if( _doc->page( pagenumber )->boundingBox().width() >  
	_doc->page( pagenumber )->boundingBox().height() )
	return LANDSCAPE;
    else
	return PORTRAIT; //Note, if a square, then portrait, too.
}

void KGVMiniWidget::setAutoOrientation()
{
    _useManualOrientation = false;
    page->setOrientation( orientation( current_page) );
    show_page( current_page ); // Shouldn't be necessary
}

void KGVMiniWidget::setManualOrientation( int orientation )
{
    _useManualOrientation = true;
    _manualOrientation = orientation;
    page->setOrientation( _manualOrientation );
    show_page( current_page ); // Shouldn't be necessary
}

int KGVMiniWidget::orientation( int pagenumber ) const
{
    int orientation;
    
    if( !_doc )
	orientation = 0;
    else
	if( _useManualOrientation )
	    orientation = _manualOrientation;
	else if( toc_text && _doc->page( pagenumber )->orientation() != NONE ) 
	    orientation = _doc->page( pagenumber )->orientation();
	else if( _doc->defaultPageOrientation() != NONE ) 
	    orientation = _doc->defaultPageOrientation();
	else if( _doc->orientation() != NONE )
	    orientation = _doc->orientation();
	else 
	    //no orientation specified in document
	    orientation = guessOrientation( pagenumber );

    return orientation;
}

void KGVMiniWidget::setAutoPageMedia()
{
    _useManualPageMedia = false;
    KDSC::BoundingBox bbox = computeBoundingBox( pageMedia( current_page ) );
    page->setBoundingBox( bbox );
    show_page( current_page ); // Shouldn't be necessary
}

void KGVMiniWidget::setManualPageMedia( int pageMedia )
{
    _useManualPageMedia = true;
    KDSC::BoundingBox bbox = computeBoundingBox( pageMedia );
    page->setBoundingBox( bbox );
    show_page( current_page ); // Shouldn't be necessary
}

int KGVMiniWidget::pageMedia( int pagenumber ) const
{   
    int pageMedia;
    
    if( !doc )
	pageMedia = 0;
    else
	if( _useManualPageMedia )
	    pageMedia = _manualPageMedia;
	else if( toc_text && doc->pages[pagenumber].media != 0 ) 
	    pageMedia = doc->pages[pagenumber].media - doc->media;
	else if( doc->default_page_media != 0 )
	    pageMedia = doc->default_page_media - doc->media;
	else
	    pageMedia = _defaultPageMedia;

    return pageMedia;
}

KDSC::BoundingBox KGVMiniWidget::computeBoundingBox( int pageMedia )
{
    if( _doc && _doc->isEPSF() 
       //Ignore malformed bounding boxes 
     && _doc->boundingBox().urx() > _doc->boundingBox().llx()
     && _doc->boundingBox().ury() > _doc->boundingBox().lly() ) {
	return _doc->boundingBox();
    } 
    else {
	int llx, lly, urx, ury;
	llx = lly = 0;
	if( pageMedia < base_papersize && doc ) {
	    urx = doc->media[pageMedia].width;
	    ury = doc->media[pageMedia].height;
	}
	else {
	    urx = papersizes[pageMedia-base_papersize].width;
	    ury = papersizes[pageMedia-base_papersize].height;
	}
	return KDSC::BoundingBox( llx, lly, urx, ury );
    }
}

void KGVMiniWidget::build_pagemedia_list()
{
    unsigned int i;
    int offset;
  
    base_papersize = 0;
    if( _doc ) 
	base_papersize = doc->nummedia;
    for( i = 0; papersizes[i].name; i++ ) 
	{} // Count the standard entries
    i += base_papersize;
  
    // if you've got an eps file need bounding box in menu too
    if( _doc && _doc->isEPSF() )
	offset=2;
    else
	offset=1;
  
    medialist.clear();

    for( i = 0; papersizes[i].name; i++ ) {
	// Skip over same paper size with small imageable area 
	// (e.g. of A4 and A4Small only A4 should be in the list)
	if( i > 0  && papersizes[i].width  == papersizes[i-1].width  
		   && papersizes[i].height == papersizes[i-1].height ) 
	    continue;
	medialist.append( papersizes[i].name );
    }
}

bool
KGVMiniWidget::setup()
{
    int oldtoc_entry_length;
  
    if( _fileName.isEmpty() ) 
	return false;
  
    // Reset to a known state.
    delete _doc;
    _doc = 0;
    doc = 0;
    current_page = -1;
    toc_text = 0;
    oldtoc_entry_length = toc_entry_length;

    // Scan document and start setting things up
    if( psfile ) {
	_doc = new KDSC::Document( _fileName );
	if( !_doc->scan( &psfile) ) {
	    delete _doc;
	    _doc = 0;
	    return false;
	}

	// Hmmm, weird :-)
	// Until the KDSC classes are complete we still need doc.
	doc = _doc->_doc;
    }
  
    buildTOC();
    build_pagemedia_list();
 
    if( current_page == -1 ) 
	current_page = 0;
 
    return true;
}

void KGVMiniWidget::buildTOC()
{
    // Build table of contents
    // Well, that's what it used to be called !!
    
    int this_page, last_page=0;

    _marklist->setAutoUpdate( false );
    _marklist->clear();
    
    if( _doc && ( !_doc->isEPSF() && _doc->numberOfPages() > 0 ||
	      _doc->isEPSF() && _doc->numberOfPages() > 1)) {
	      
	unsigned int maxlen = 0;
	unsigned int i, j;
     
	// Find the longest pagelabel
	if(  _useFancyPageLabels ) {
	    for( i = 0; i < _doc->numberOfPages(); i++ )
		maxlen = QMAX( maxlen, _doc->page( i )->label().length() );
	}
	else {
	    double x;
	    x = _doc->numberOfPages();
	    maxlen = (int)( log10(x) + 1 );
	}
	
	toc_entry_length = maxlen + 3;
	toc_length = _doc->numberOfPages() * toc_entry_length - 1;
	toc_text = 1;
      
	if( _useFancyPageLabels )
	    for( i = 0; i < _doc->numberOfPages(); i++ ) {
		if( doc->pageorder == DESCEND )
		    j = ( _doc->numberOfPages() - 1 ) - i;
		else 
		    j = i;
		this_page = _doc->page( j )->label().toInt();
		last_page = this_page;
	    } 
	
	// Set 0 filename for gs -- use pipe.
	page->setFileName( QString::null );
      
	// finally set marked list
	QString s, tip;
	for( i = 1; i <= _doc->numberOfPages(); i++ ) {
	    j = _doc->numberOfPages() - i;
	    tip = _doc->page( j )->label();

	    if( !_useFancyPageLabels )
		s.setNum (j+1);
	    else
		s=tip;

	    _marklist->insertItem( s, 0, tip );
	}
    } 
    else {
	toc_length = 0;
	toc_entry_length = 3;
	page->setFileName( _fileName );
	QString s("1");
	_marklist->insertItem( s, 0 );
    }
   
    _marklist->setAutoUpdate( true );
    _marklist->update();
   
    if( doc ) {
	if( _doc->numberOfPages() == 0 )
	    page_total_label = i18n("of 1    ");
	else if( _doc->numberOfPages() > 0 && _doc->numberOfPages() < 10 ) 
	    page_total_label = i18n("of %1    ").arg(_doc->numberOfPages());
	else if( _doc->numberOfPages() < 100 ) 
	    page_total_label = i18n("of %1  ").arg(_doc->numberOfPages());
	else if( doc ) 
	    page_total_label = i18n("of %1").arg(_doc->numberOfPages());
	else 
	    page_total_label = "	  ";
    }
}

void KGVMiniWidget::new_file( int number )
{
    bool layout_changed = false;

    // return to document defaults
    _useManualOrientation = false;
    _useManualPageMedia = false;

    if( setup() )
	layout_changed = true;

    setMagstep( _magstep );
  
    show_page( number );
}

void
KGVMiniWidget::show_page( int pagenumber )
{
    kdDebug(4500) << "KGVMiniWidget::show_page( " << pagenumber << " )" << endl;

    if( !page || _fileName.isEmpty() ) {
	return;
    }

    // Coerce page number to fall in range
    if( toc_text ) {
	if( ( unsigned int)pagenumber >= _doc->numberOfPages() ) {
	    pagenumber = _doc->numberOfPages() - 1;
	}    
	if( pagenumber < 0 ) {
	    pagenumber = 0;
	}
    }

    // First layout the page correctly.
    // Don't update the page, before we've setup all properties.
    page->setDelayedLayout( true );

    page->setOrientation( orientation( pagenumber ) );
    KDSC::BoundingBox bbox = computeBoundingBox( pageMedia( pagenumber ) );
    page->setBoundingBox( bbox );
	
    // Trigger the relayout of the page.
    page->setDelayedLayout( false );
   
    // Send the page to the interpreter.
    if( toc_text ) {
	current_page = pagenumber;
	if( page->isInterpreterReady() ) { 
	    // Interpreter ready - Fire off next page
	    page->nextPage();
	}
	else {
	    // Start interpreter and send preamble
	    page->enableInterpreter();
	    page->sendPS( psfile, _doc->prologOffset(), false );
	    page->sendPS( psfile, _doc->setupOffset(), false );
	}
	// Send current page
	page->sendPS( psfile, _doc->page( current_page )->offset(), false );
    } 
    else {
	if( !page->isInterpreterRunning() ) {
	    // This is not a structured document -- start interpreter
	    page->enableInterpreter();
	    if( !doc )
		page->disableInterpreter();
	}
	else if( page->isInterpreterReady() ) {
	    page->nextPage();
	}
	else {
	    /*
	    KNotifyClient::userEvent 
	      (i18n("KGhostview cannot load the document, \"%1\".\n"
		    "It appears to be broken.").arg( _fileName ),
	       KNotifyClient::Messagebox);
	    page->disableInterpreter();
	    psfile=0;

	    //TODO: More to do to turn off display?
	    */
	    return;
	}
    }
    
    //
    // Well that takes care of sending the postscript.
    // Now update the page label on the status line
    //
    if(toc_text) {
	page_string = i18n( "Page" );
	if( pagenumber == -1 )
	    page_string += QString( " 1 " );
	else
	    if( _useFancyPageLabels ) {
		QString label( _doc->page( current_page )->label() );
		page_string += QString( " %1 \"%2\" " ).arg( pagenumber + 1 )
						       .arg( label );
	    }
	    else
		page_string += QString( " %1 " ).arg( pagenumber + 1 );
	
	page_label_text=page_string + page_total_label;
	
	emit setStatusBarText( page_label_text );
    }

    emit newPageShown( pagenumber );
}

void KGVMiniWidget::setMagstep( unsigned int magstep )
{
    float xdpi, ydpi;
    xdpi = _defaultXdpi;
    ydpi = _defaultYdpi;
    _magstep = magstep;
    
    magnify( xdpi, _magstep );
    magnify( ydpi, _magstep );
    page->setResolution( xdpi, ydpi );
    show_page( current_page );
}

void
KGVMiniWidget::magnify( float& dpi, unsigned int magstep )
{
    if( magstep < shrink_magsteps )
	dpi = (int)( dpi * magstep / shrink_magsteps );
    else
	dpi = (int)( dpi + 2 * dpi * ( magstep - shrink_magsteps )/ expand_magsteps );
}

void
KGVMiniWidget::setOriginalURL (const KURL &url)
{
  origurl = url;
}

void
KGVMiniWidget::writeSettings()
{
    KConfig *config = KGVFactory::instance()->config();
    config->setGroup( "KGVMiniWidget" );   
    config->writeEntry( "FancyPageLabels", _useFancyPageLabels );
    page->writeSettings(); //calls config->sync()
}

bool
KGVMiniWidget::convertFromPDF()
{
    if( !tmppdf.isEmpty() )
	QFile::remove( tmppdf );
  
    const char *cmd_convert_pdf = 
		"%s -q -dNODISPLAY -sPSFile=%s -dNOPAUSE  %s -c quit";
    QCString cmd;
    tmppdf.sprintf ( "%s/kgvtmp_unpdf_%d", _PATH_TMP, getpid());
    cmd.sprintf( cmd_convert_pdf, _interpreterPath.local8Bit().data(),
	QFile::encodeName( tmppdf ).data(), 
	QFile::encodeName( _fileName ).data());
  
    //TODO -- timeout/fail on this conversion (it can hang on a bad pdf)
    //TODO -- use output from gs (leave out -q) to drive a progress bar
  
    int r = system( cmd );
    if( r ) {
	//TODO -- error message (can't open, strerr())
	return false;
    }
    
    return true;
}

void
KGVMiniWidget::enableFancyPageLabels( bool e )
{
    if( _useFancyPageLabels != e ) {
	_useFancyPageLabels = e;
	buildTOC();
	show_page( current_page );
    }
}


