/****************************************************************************
**
** 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).
 */


//TODO - check orientations


#define PAGELIST_WIDTH 75

/*const int ID_VT_MAG=0;
const int ID_VT_ORIENT=1;
const int ID_VT_MEDIA=2;
*/

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

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

#include <kapp.h>
#include <kconfig.h>
//#include <kiconloader.h>
#include <kfiledialog.h>
//#include <kkeydialog.h>
#include <klocale.h>
//#include <kmenubar.h>
#include <kmessagebox.h>
#include <kmimemagic.h>
#include <kio/netaccess.h>

#include <config.h>
#include "gotodialog.h"
#include "infodialog.h"
#include "interpreterdialog.h"
#include "kgv_miniwidget.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 "scrollbox.h"

#include "kgv_miniwidget.moc"

KGVMiniWidget::KGVMiniWidget( QWidget *parent, const char *name )
    : QWidget(parent, name)
{   
  // Initialise all the variables declared in this class.
  // I ususally forget to do a few resulting in nasty seg. faults !
  
  oldfilename = "";
  filename = "";
  psfile=0;
  doc=0;
  olddoc=0;
  mGotoDialog=0;
  bfancypagelabels=false;
  bspecialnoupdate=false;
 

  current_page=0;
  num_parts=0;
  for(int part_count=0;part_count<10;part_count++)
    pages_in_part[part_count]=0;

  
  shrink_magsteps = 10;
  current_magstep = magstep = 10;
  expand_magsteps = 10;
  default_xdpi = 75.0;
  default_ydpi = 75.0;
  default_pagemedia = 1;
  document_media = 0;
  base_papersize=0;
  orientation = 1;
  force_orientation = false;
  force_pagemedia = false;
  current_llx = 0;
  current_lly = 0;
  current_urx = 0;
  current_ury = 0;
  


  QHBoxLayout *hlay = new QHBoxLayout( this, 0, 0 );
  QVBoxLayout *vlay = new QVBoxLayout( hlay );
  
  scrollBox = new ScrollBox( this , "scrollbox" );
  scrollBox->setMinimumWidth( PAGELIST_WIDTH );
  scrollBox->setMinimumHeight( PAGELIST_WIDTH );
  vlay->addWidget( scrollBox );
  
  marklist = new MarkList( this );
  CHECK_PTR( marklist );

  marklist->setMinimumWidth( PAGELIST_WIDTH );
  vlay->addWidget( marklist, 1 );
  marklist->setSelectColors( colorGroup().highlight(), 
			     colorGroup().highlightedText() );
  connect( marklist, SIGNAL(selected( int )), SLOT(pageActivated( int )) );
  
  divider = new QFrame( this );
  CHECK_PTR( divider );
  divider->setFrameStyle( QFrame::Panel | QFrame::Raised );
  divider->setLineWidth( 1 );
  divider->setMinimumWidth( 3 );
  hlay->addWidget( divider );
  
  page = new KPSWidget( this );
  CHECK_PTR ( page );
  hlay->addWidget( page, 1);
  
  connect( scrollBox, SIGNAL(valueChanged(QPoint)),
	   page, SLOT(slotScroll(QPoint)) );
  connect( page, SIGNAL(pageSizeChanged( QSize )),
	   scrollBox, SLOT(setPageSize( QSize )) );
  connect( page, SIGNAL(viewSizeChanged( QSize )),
	   scrollBox, SLOT(setViewSize( QSize )) );
  connect( page, SIGNAL(currentPosChanged( QPoint )),
	   scrollBox, SLOT(setViewPos( QPoint )) );
  

  printerName = "lp0";
  readSettings();


  //
  //	READ SETTINGS AND SET OPTIONS MENU, SET LAST OPENED FILES
  //
  setName();
  show();
  
  if (psfile)
    setup();
}

void
KGVMiniWidget::pageActivated( int pg ) // Duda 16/3/98
{
  if (!bspecialnoupdate)
    show_page(pg);
}

KGVMiniWidget::~KGVMiniWidget()
{
  if (mGotoDialog!=0)
    delete mGotoDialog;
  if (!tmpfile1.isEmpty())
    unlink (tmpfile1);
  if (!tmppdf.isEmpty())
    unlink (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.data(), fdate.data() );
  mInfoDialog->exec();
  delete mInfoDialog;
}

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


void
KGVMiniWidget::readSettings()
{
  //Don't set the group here.

  KConfig *config = kapp->config();

  showMarkList (config->readBoolEntry ("ShowMarkList", true));
  bfancypagelabels = config->readBoolEntry ("FancyPageLabels", false);

  int i = config->readNumEntry( "Magstep", 10);
  if( i<20 && i>0 )
    magstep = i;
  
  set_new_magstep();
  
  //Orientation should be determined by the document at the
  // outset.
  //orientation = config->readNumEntry( "Orientation",  1);
  //set_new_orientation(0);
}

void
KGVMiniWidget::shrinkWrap()
{
  int new_width=0;
  
  if ( !psfile ) 
    return;
  
  new_width=page->fullView->width()+(x()+width()-geometry().right())
    +(geometry().left()-x())+2;
  
  if( page->vertScrollBar->isVisible() )
    new_width+=page->vertScrollBar->width();
  
  if( marklist->isVisible() )
    new_width+=PAGELIST_WIDTH+3;
  
  QWidget *d = QApplication::desktop();
  int w=d->width()-10;
  if( new_width > w )
    new_width = w;
 
  hintwidth = new_width;
  emit sizeHintChanged ();
}

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

void
KGVMiniWidget::setName()
{
  setCaption (origurl.filename());
}


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

  unsigned int savepage=current_page;
 
  struct stat sbuf;
  stat( filename, &sbuf );
  if (sbuf.st_mtime > mtime)
    {
      openFile (filename);
 
      if (doc->numpages >= savepage)
        show_page( savepage );
    }
  
}

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

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


//
//	SLOTS UP NEXT
//


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

void
KGVMiniWidget::readDown()
{
  if( !page->readDown() )
    nextPage();
}

void
KGVMiniWidget::scrollUp()
{
  page->scrollUp();
}

void
KGVMiniWidget::scrollDown()
{
  page->scrollDown();
}

void
KGVMiniWidget::scrollRight()
{
  page->scrollRight();
}

void
KGVMiniWidget::scrollLeft()
{
  page->scrollLeft();
}



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 )
{
  current_page = page;
  marklist->select(current_page);
}



void
KGVMiniWidget::print()
{
  //printf("KGVMiniWidget::print\n");
  
  pd = new PrintDialog( this, "print dialog", doc->numpages, 
			( marklist->markList()->count() > 0 ) );
  pd->setCaption(i18n("Print"));
  
  
  
  
  if( pd->exec() ) {
    printStart( pd->pgMode, pd->cbOrder->isChecked(),
		pd->cbFile->isChecked(),
		pd->printerName, pd->spoolerCommand,
		pd->printerVariable,
		QString( pd->leStart->text() ).toInt(),
		QString( pd->leEnd->text() ).toInt() );
  }

  delete pd;
}


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

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


/*
void
KGVMiniWidget::zoom ( float zoom_factor )
{

  page->disableInterpreter();
  page->xdpi=zoom_factor*default_xdpi;
  page->ydpi=zoom_factor*default_ydpi;
  
  page->layout();
  page->resize(page->width(), page->height());
  page->repaint();
  show_page(current_page);
  shrinkWrap();
}
*/

void
KGVMiniWidget::nextPage()
{
  int new_page = 0;
  
  if (toc_text)
    {
      new_page = current_page + 1;
      if ((unsigned int) new_page >= doc->numpages)
	return;
    }
  marklist->select(new_page);

  page->scrollTop();
}

void
KGVMiniWidget::goToStart()
{
  marklist->select(0);
  page->scrollTop();
}

void
KGVMiniWidget::goToEnd()
{
  marklist->select(doc->numpages-1);
  page->scrollTop();
}


void KGVMiniWidget::prevPage()
{
  int new_page = 0;
  
  if (toc_text)
    {
      new_page = current_page - 1;
      if (new_page < 0)
	return;
    }
	
  marklist->select(new_page);
  page->scrollTop();
}

void
KGVMiniWidget::printStart( int mode, bool reverseOrder, 
			   bool toFile,
			   QString printerName, QString spoolerCommand,
			   QString printerVariable,
			   int pgStart, int pgEnd )
{
  QStrList *ml = new QStrList;
  
  switch( mode )
    {
    case PrintDialog::All:
      for( unsigned int j = 0; j< doc->numpages; j++ )
	ml->append( marklist->text( j ) );
      break;
      
    case PrintDialog::Current:
      ml->append( marklist->text( current_page ) );
      break;
      
    case PrintDialog::Marked:
      ml = marklist->markList();
      break;
      
    case PrintDialog::Range:
      if ( pgStart <= pgEnd )
	for( int j = pgStart-1; j< pgEnd; j++ )
	  ml->append( marklist->text( j ) );
      else 
	for( int j = pgEnd-1; j< pgStart; j++ )
	  ml->append( marklist->text( j ) );
      break;
    }
	
  if ( reverseOrder )
    {
      QStrList *sl = new QStrList;
      for( ml->last(); ml->current(); ml->prev() )
	sl->append( ml->current() );
      *ml = *sl;
      delete sl;
    }
  
  QString error;
  
  if ( toFile )
    {
      error = printToFile( ml );
    } 
  else
    { 
      error = printToPrinter( printerName, spoolerCommand, printerVariable,
			      ( mode == PrintDialog::All ), ml );
    }
  
  //TODO -- KNotifyClient
  if ( !error.isNull() ) 
    KMessageBox::error( 0, error, i18n( "Error printing" ));
  
  delete ml;
}

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

QString
KGVMiniWidget::printToFile( QStrList *ml )
{
  FILE *pswrite;
  bool bdeleteml=false;
  
  if (ml==0L) //then print all
    {
      ml = new QStrList;
      bdeleteml=true;
      for( unsigned int j = 0; j< doc->numpages; j++ )
	ml->append( marklist->text( j ) );
    }
  
  /*	
	//No!  Printing all to a file is a desirable,
	  often-requested feature.  (Think: web browsing, print preview)
	  //dsweet

	if ( allMode ) {
	QString buf( i18n(	"You chose to print all pages to a file.\n"
	"This would produce a document identical to\n"
	"that currently loaded into the viewer.\n"
	"There is no need to print all pages into a new file.") );
	return buf;
	}*/
  
  
  QString usefile;
  if (format==PDF)
    {
      if (convertFromPDF())
	usefile = tmppdf;
      else
	return 
	  QString (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)");

  //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()) 
    {
      if (bdeleteml)
	delete ml;
      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( s.data(), "w" ) ) == 0L )
    {
      QString buf;
      buf = i18n("Attempt to open file for writing failed.\n\n"
		 "Error: %1\n")
	.arg( strerror(errno) );
      if (bdeleteml)
	delete ml;
      return buf;
    }
  else
    {
      psCopyDoc( pswrite, ml );
      fclose( pswrite );
      if (bdeleteml)
	delete ml;
      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;
    }

  if (bdeleteml)
    delete ml;

}

QString
KGVMiniWidget::printToPrinter( QString printerName, QString spoolerCommand,
			       QString printerVariable, 
			       bool allMode, QStrList *ml )
{
  //    printf("KGhostview::print_file\n");
  
  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("\"");
  
  if ( !printerName.isEmpty() ) 
    {
    if ( !printerVariable.isEmpty() ) 
      {
	setenv( printerVariable.data(), printerName.data(), true );
      }
    else
      return( QString( i18n( "Set Environment variable "
			     "(to PRINTER or LPDEST for instance)"
			     "for Printer name to be taken into "
			     "account." ) ) );
    }


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


  oldsig = signal( SIGPIPE, SIG_IGN );
  printer = popen( spoolerCommand.data(), "w" );
  
  if ( toc_text && !allMode ) 
    {
      psCopyDoc( printer, ml );
    } 
  else
    {
      FILE *tmpfile = ::fopen( 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, QStrList *ml )
{
  
  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( filename, "r" );
  
  pages = ml->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 );
  
  QStrListIterator it( *ml );
  
  //TODO -- Check that a all doc attibutes are copied
  //TODO -- fix gz and pdf copying


  for(; it.current(); ++it ) 
    {
      i = QString( it.current() ).toInt() - 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

//*********************************************************************************
//
//	Look out below !! This stuff is pretty messy.
//
//*********************************************************************************


bool
KGVMiniWidget::same_document_media()
{
  //printf("KGVMiniWidget::same_document_media\n");
  
  unsigned int j;
  
  if (olddoc == 0 && doc == 0)
      return true;
  
  if (olddoc == 0 || doc == 0) 
    return false;
  if (olddoc->nummedia != doc->nummedia) 
    return false;
  // Exclusive OR old document was EPS and new document is EPS
  if ((olddoc->epsf || doc->epsf) && !(olddoc->epsf && doc->epsf)) 
    {
      //fprintf(stderr, "Old document was EPS and this isn't or vice versa\n");
      return false;
    }
  for (j = 0; j < doc->nummedia; j++)
    if (strcmp(olddoc->media[j].name, doc->media[j].name)) return false;
	
  return false;
}

bool
KGVMiniWidget::openFile( QString &name )
{
  FILE *fp;
  struct stat sbuf;
  
  if (!tmpfile1.isEmpty())
    unlink (tmpfile1);
  
  //printf ("opening [%s]\n", (const char*)name);

  if (strcmp(name, "-")) 
    {
      //TODO -- Use KProcess instead of system!

      format = PS;


      QString mimetype
	( KMimeMagic::self()->findFileType (name)->mimeType() );
      if (mimetype == "application/x-gzip")
	{
	  const char *cmd_uncompress = "gzip -d -c %s > %s";
	  char cmd [2048];
	  char filename_unc [1024];
	  sprintf ( filename_unc, "%s/kgvtmp_ungz_%d",
		    _PATH_TMP, getpid());
	  sprintf(cmd, cmd_uncompress, (const char *)name, filename_unc);

	  tmpfile1 = filename_unc;
	  int r=system (cmd);
	  if (r==0)
	    {
	      name = filename_unc;
	      QString mimetypepdf
		( KMimeMagic::self()->findFileType (name)->mimeType() );

	    }
	  else
	    {
	      //TODO -- couldn't open file error message
	      return false;
	    }
	}

      if (mimetype == "application/pdf")
	format = PDF;


      

      //      printf ("open [%s]\n", (const char *)name);
      if ( ( fp = fopen(name, "r") ) == 0 ) 
	{
	  
	  QString s;
	  s = i18n("The document could not be opened.\n"
		   "No document has been loaded.\n\n"
		   "%1\nError: %2")
	    .arg( name )
	    .arg( strerror(errno) );
	  
	  //TODO - KNotify
	  KMessageBox::error(0, s, i18n("Error opening file"));
	  
	  return false;
	  
	} 
      else
	{
	  oldfilename = filename;
	  filename = name;
	  if ( psfile ) 
	    fclose( psfile );
	  
	  psfile = fp;
	  stat( filename, &sbuf );
	  mtime = sbuf.st_mtime;
	  
	  new_file( 0 );
	  setName();

	  //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;
	}
      
    } 
  else
    {
      oldfilename = filename;
      filename = name;
      if ( psfile ) 
	fclose( psfile );
      psfile = 0;
      new_file(0);
      
      setName();
    }
  
  //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;
}

int
KGVMiniWidget::autoOrient (int pagenumber)
{
  //if width > height  (only useful for BBOX, right?)
  if (doc->pages[pagenumber].boundingbox[2] >  
      doc->pages[pagenumber].boundingbox[3])   
    return LANDSCAPE;
  else
    return PORTRAIT; //Note, if a square, then portrait, too.
}

bool
KGVMiniWidget::set_new_orientation(int number)
{
  bool changed = false;
  bool from_doc = false;
  int new_orientation;
  
  if (force_orientation) 
    new_orientation = orientation;
  else
    {
      if (doc)
	{
	  if (toc_text && doc->pages[number].orientation != NONE) 
	    {
	      new_orientation = doc->pages[number].orientation;
	      from_doc = true;
	    }
	  else if (doc->default_page_orientation != NONE) 
	    {
	      new_orientation = doc->default_page_orientation;
	      from_doc = true;
	    } 
	  else if (doc->orientation != NONE) 
	    {
	      new_orientation = doc->orientation;
	      from_doc = true;
	    } 
	  else //not orientation specified in document
	    new_orientation = autoOrient (number);
	}
      else //no document, even!
	    new_orientation = orientation;
    }
  
  /* If orientation changed,
   * stop interpreter and setup for new orientation. */
  if (new_orientation != current_orientation) 
    {
      //printf("New orientation\n");
      page->disableInterpreter();


      page->orientation =  new_orientation;


      current_orientation = new_orientation;
      changed = true;
    } 
  
  return changed;
}

// Set new pagemedia
bool
KGVMiniWidget::set_new_pagemedia( int number )
{
  //printf("KGhostview::set_new_pagemedia\n");
  
  int new_pagemedia=0;
  int new_llx=0;
  int new_lly=0;
  int new_urx=0;
  int new_ury=0;
  bool changed = false;
  bool from_doc = false;
  
  //printf("******	Set new media\n");
  
  if (force_document_media)
    {
      new_pagemedia = document_media;
    }
  else if (force_pagemedia)
    {
      new_pagemedia = default_pagemedia;
    } 
  else
    {
      if (doc) 
	{
	if (toc_text && doc->pages[number].media != 0) 
	  {
	    new_pagemedia = doc->pages[number].media - doc->media;
	    from_doc = true;
	  } 
	else if (doc->default_page_media != 0) 
	  {
	    new_pagemedia = doc->default_page_media - doc->media;
	    from_doc = true;
	  }
	else
	  {
	    new_pagemedia = default_pagemedia;
	  }
	} 
      else
	{
	  new_pagemedia = default_pagemedia;
	}
    }
  
  //    if (new_pagemedia != current_pagemedia)
  //      {
  //fprintf(stderr, "New media\n");
  
  current_pagemedia = new_pagemedia;
  //    } 
  
  // Compute bounding box
  if (   !force_document_media &&
	 !force_pagemedia &&
	 doc && doc->epsf &&
	 //Ignore malformed bounding boxes 
	 (doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
	 (doc->boundingbox[URY] > doc->boundingbox[LLY])
	 )
    {
      new_llx = doc->boundingbox[LLX];
      new_lly = doc->boundingbox[LLY];
      new_urx = doc->boundingbox[URX];
      new_ury = doc->boundingbox[URY];
      //text=XmStringCreateLtoR("EPS box", XmFONTLIST_DEFAULT_TAG);
      //printf("EPS box\n");
    } 
  else
    {
      //printf("Trying to compute size ! base papersize = %d\n",
      //base_papersize);
      new_llx = new_lly = 0;
      if (new_pagemedia < base_papersize && doc) 
	{
	  new_urx = doc->media[new_pagemedia].width;
	  new_ury = doc->media[new_pagemedia].height;
	  //printf("%s\n", doc->media[new_pagemedia].name);
	  // text=XmStringCreateLtoR(doc->media[new_pagemedia].name
	  //	, XmFONTLIST_DEFAULT_TAG);
	}
      else
	{
	  new_urx = papersizes[new_pagemedia-base_papersize].width;
	  new_ury = papersizes[new_pagemedia-base_papersize].height;
	  //printf("%s\n", papersizes[new_pagemedia-base_papersize].name);
	  // text=XmStringCreateLtoR(
	  // 	papersizes[new_pagemedia-base_papersize].name
	  // 	, XmFONTLIST_DEFAULT_TAG);
	}
    }
  
  //printf("new width = %d, current width = %d\n", new_urx, current_urx);
  //printf("new h = %d, current h = %d\n", new_ury, current_ury);
  
  //printf("new x offset %d : new y offset %d\n", new_llx, new_lly);
  
  // If bounding box changed, setup for new size.
  if ((new_llx != current_llx) || (new_lly != current_lly) ||
      (new_urx != current_urx) || (new_ury != current_ury)) 
    {
      //printf("Change media\n");
      page->disableInterpreter();
      changed = true;
      current_llx = new_llx;
      current_lly = new_lly;
      current_urx = new_urx;
      current_ury = new_ury;
      page->llx = current_llx;
      page->lly = current_lly;
      page->urx = current_urx;
      page->ury = current_ury;
    }
  
  /* XtSetArg(args[0], XmNselectedItem, text);
     //XtSetValues(viewControlMediaCombo, args, ONE); */
  
    
  return changed;
}


void
KGVMiniWidget::build_pagemedia_list()
{
  //printf("KGVMiniWidget::build_pagemedia_menu\n");
  
  unsigned int i;
  int offset;
  
  if (same_document_media()) 
    {
      //printf("Same document media\n");
      return;
    }
  force_document_media = false;
  
  /* Build the Page Media menu */
  /* the Page media menu has two parts.
   *  - the document defined page medias
   *  - the standard page media defined from Adobe's PPD
   */
  
  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->epsf)
    offset=2;
  else
    offset=1;
  
  medialist.clear();

  for (i = 0; papersizes[i].name; i++) 
    {
      if (i > 0) 
	// Skip over same paper size with small imageable area
	if ((papersizes[i].width == papersizes[i-1].width) &&
	    (papersizes[i].height == papersizes[i-1].height)) 
	  continue;
      medialist.append (papersizes[i].name);
    }

}



bool
KGVMiniWidget::setup()
{
  //    printf("KGVMiniWidget::setup\n");

  int oldtoc_entry_length;
  int k;
  
  
  if ( filename.isEmpty() ) 
    return false;
  
  //printf("Gone into setup\n");
  // Reset to a known state.
  psfree( olddoc );
  //printf("Freed olddoc\n");
  olddoc = doc;
  doc = 0;
  current_page = -1;
  toc_text = 0;
  oldtoc_entry_length = toc_entry_length;
  //printf("Next - pages in part\n");
  for(k=0;k<10;k++)
    pages_in_part[k]=0;
  num_parts=0;
  
  
  //printf("Reset state\n");
  
  // Scan document and start setting things up
  if (psfile) 
    {
      //printf ("Scan file -");
      //doc = psscan(psfile); // 18/3/98 Jake Hamby patch
      
      // 18/3/98 Jake Hamby patch
      
      char *filename_dscP = 0;
      char *filename_uncP = 0;
      const char *cmd_scan_pdf = "gs -dNODISPLAY -dQUIET -sPDFname=%s -sDSCname=%s pdf2dsc.ps -c quit";
      const char *cmd_uncompress = "gzip -d -c %s > %s";
      doc = psscan(&psfile, filename, _PATH_TMP"/kghostview", &filename_dscP,
		   cmd_scan_pdf, &filename_uncP, cmd_uncompress);
      
      // UNIX won't delete these files until the last reference is closed,
      // so we can unlink() them now
      
      if(filename_dscP) 
	{
	unlink(filename_dscP);
	free(filename_dscP);
	}
      
      if (filename_uncP) 
	{
	  unlink(filename_uncP);
	  free(filename_uncP);
	}
      
      // end of patch
      
      //if (doc == 0) //printf(" 0 FILE - ");
      //printf ("scanned\n");
    }
  
  buildTOC(0);
  
  build_pagemedia_list();
  //printf("Built pagemedia menu\n");
  
  // Reset ghostscript and output messages popup
  if (
      !doc || !olddoc ||
      strcmp(oldfilename, filename) ||
      olddoc->beginprolog != doc->beginprolog ||
      olddoc->endprolog != doc->endprolog ||
      olddoc->beginsetup != doc->beginsetup ||
      olddoc->endsetup != doc->endsetup
      )
    {
      //printf("reset messages\n");
      
      page->disableInterpreter();
      //printf("Disabled Interpreter\n");
      
      /**************************************************************
       *	XtUnmanageChild(infopopup);
       *	XmTextReplace(infotext, 0, output_position, 0_string);
       *	info_up = false;
       *	XtSetArg(args[0], XmNcursorPosition, 0);
       *	XtSetValues(infotext, args, ONE);
       *	output_position=0;
       **************************************************************/
    }
  
  if(current_page==-1) 
    current_page=0;
  
  //printf("Setup finished\n");
  return oldtoc_entry_length != toc_entry_length;
}


void
KGVMiniWidget::buildTOC(int pagenumber)
{
  //
  // 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->epsf && doc->numpages > 0 ||
	      doc->epsf && doc->numpages > 1)) 
    {
      int maxlen = 0;
      unsigned int i, j;
      bool useful_pg_labels = false;
      
      if (doc->numpages == 1) 
	useful_pg_labels = true;

      for (i = 1; i < doc->numpages; i++)
	if ( (useful_pg_labels = 
	      (useful_pg_labels ||
	       strcmp(doc->pages[i-1].label, doc->pages[i].label)))) 
	  break;

      //Many users might still like to use 1, 2, 3, ... instead of
      // the document-specified page names.
      useful_pg_labels |= bfancypagelabels;

      if (useful_pg_labels) 
	{
	  for (i = 0; i < doc->numpages; i++) 
	    if((unsigned int)maxlen<strlen(doc->pages[i].label))
	      maxlen=strlen(doc->pages[i].label);
	}
      else
	{
	  double x;
	  x = doc->numpages;
	  maxlen = (int)( log10(x) + 1 );
	}
      toc_entry_length = maxlen + 3;
      toc_length = doc->numpages * toc_entry_length - 1;
      toc_text = 1;
      
      for (i = 0; i < doc->numpages; i++) 
	{
	if (useful_pg_labels) 
	  {
	    if (doc->pageorder == DESCEND) 
	      {
		j = (doc->numpages - 1) - i;
	      }
	    else
	      {
		j = i;
	      }
	    this_page=atoi(doc->pages[j].label);
	    if(last_page>this_page) 
	      {
		num_parts++;
	      }
	    if (num_parts<10) pages_in_part[num_parts]++;
	    
	    last_page=this_page;
	  } 
	else
	  {
	  }
      }
      page->filename = QString::null;
      //printf("Set 0 filename for gs -- use pipe\n");
      
      QString s, tip;
      // finally set marked list
      for ( i = 1; i <= doc->numpages; i++) 
	{
	  j = doc->numpages-i;
	  tip = doc->pages[j].label;

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

	  marklist->insertItem( s, 0, tip );
	}
      
    } 
  else
    {
      toc_length = 0;
      toc_entry_length = 3;
      page->filename = filename;
      //printf("Set filename -- gs will open this file\n");
      QString s("1");
      marklist->insertItem( s, 0 );
    }
  //printf("Parsed document structure\n");
  
  //marklist->setAutoUpdate( true );
  //marklist->select(0);
  //marklist->update();
  
  
  //printf("number of parts %d\n", num_parts);
  if (doc) 
    {
      if (num_parts>10 || (unsigned int)num_parts==doc->numpages) 
	{
	  num_parts=0;
	  pages_in_part[0]=doc->numpages;
	}
      if(num_parts==0) 
	{
	  if(doc->numpages==0) 
	    {
	      sprintf(page_total_label, i18n("of 1    "));
	    }
	  else if(doc->numpages>0 && doc->numpages<10) 
	    {
	      sprintf(page_total_label, i18n("of %d    "), doc->numpages);
	    } 
	  else if (doc->numpages<100) 
	    {
	      sprintf(page_total_label, i18n("of %d  "), doc->numpages);
	    }
	  else if (doc) 
	    {
	      sprintf(page_total_label, i18n("of %d"), doc->numpages);
	    }
	  else 
	    {
	      sprintf(page_total_label, "         ");
	    }
	}
      else 
	{
	  if(pages_in_part[0]==0) 
	    {
	      sprintf(page_total_label, i18n("of 1    "));
	    } 
	  else if(pages_in_part[0]>0 && pages_in_part[0]<10) 
	    {
	      sprintf(page_total_label, i18n("of %d    "), pages_in_part[0]);
	    } 
	  else if (pages_in_part[0]<100) 
	    {
	      sprintf(page_total_label, i18n("of %d  "), pages_in_part[0]);
	    }
	  else if (doc) 
	    {
	      sprintf(page_total_label, i18n("of %d"), pages_in_part[0]);
	    } 
	  else
	    {
	      sprintf(page_total_label, "         ");
	    }
	  
	  sprintf(part_total_label, i18n("of %d"), num_parts+1);
	}
    }

  marklist->setAutoUpdate( true );
  marklist->update();
  marklist->select(pagenumber);
}

void
KGVMiniWidget::new_file( int number )
{
  //printf("KGVMiniWidget::new_file\n");
  
  bool layout_changed = false;

  //return to document defaults
  force_orientation = false;
  force_pagemedia = false;

  //page->disableInterpreter();
  if (setup())
    layout_changed = true;

  page->setDocumentPresent (true);
  
  // Coerce page number to fall in range
  if (toc_text) 
    {
      if ((unsigned int)number >= doc->numpages) 
	number = doc->numpages - 1;
      if (number < 0)
	number = 0;
    }
  
    if (set_new_orientation(number)) 
      layout_changed = true;
    if (set_new_pagemedia(number)) 
      layout_changed = true;
    if (layout_changed) 
      {
    	page->layout();
	show_page (number);
      }
}

void
KGVMiniWidget::show_page(int number)
{
  //    printf("KGVMiniWidget::show_page\n");
  
  struct stat sbuf;
  bool new_orient = false, new_media = false;
  
  if ( filename.isEmpty() ) 
    {
      //printf("No file !\n");
      return;
    }

    if (psfile) 
      {
    	//printf("Oh does it go into psfile ?\n");
    	if (!stat(filename, &sbuf) && mtime != sbuf.st_mtime) 
	  {
	    fclose(psfile);
	    psfile = fopen(filename, "r");
	    mtime = sbuf.st_mtime;
	    oldfilename = filename;
	    new_file(number);
	  }
      }
    
    // Coerce page number to fall in range
    if (toc_text) 
      {
	if ((unsigned int)number >= doc->numpages) 
	  number = doc->numpages - 1;
	if (number < 0) 
	  number = 0;
      }
    
    //printf("Hmm shouldn't this whole thing be inside the if(psfile) ?\n");
    
    new_orient=set_new_orientation(number);
    new_media=set_new_pagemedia(number);
    
    //printf("new_orient %d, new_media %d\n", new_orient, new_media);
    
    if (new_orient || new_media)
      page->layout();
    
    if (toc_text) 
      {
	current_page = number;
	if ( page->isInterpreterReady() ) 
	  {
	    //printf("Interpreter ready - Fire off next page\n");
	    page->nextPage();
	    
	  }
	else
	  {
	    //printf("Start interpreter and send preamble\n");
	    page->enableInterpreter();
	    page->sendPS(psfile, doc->beginprolog,
			 doc->lenprolog, false);
	    page->sendPS(psfile, doc->beginsetup,
			 doc->lensetup, false);
	    
	  }
	//printf("Send page %d\n", current_page);
	page->sendPS(psfile, doc->pages[current_page].begin,
		     doc->pages[current_page].len, false);
	
      } 
    else
      {
	if ( !page->isInterpreterRunning() ) 
	  {
	    //printf("This is not a structured document -- start int.\n");
	    page->enableInterpreter();
		if (!doc)
			page->disableInterpreter();
	    
	  } 
	else if ( page->isInterpreterReady() ) 
	  {
	    page->nextPage();
	  } 
	else
	  kapp->beep();
      }


    
    //
    // Well that takes care of sending the postscript.
    // Now update the page label on the status line
    //
    
    if(toc_text) 
      {
	if(num_parts==0) 
	  {
	    part_string = i18n("Sc.1 ");
	    sprintf(part_total_label, i18n("of 1    "));
	    if(number==-1)
	      page_string = i18n("P.1 ");
	    else
	      page_string = i18n("P.%1 ").arg(number+1);
	  } 
	else 
	  {
	    int cumulative_pages=0;
	    int k, part;
	    
	    
	    for(k=0;k<10;k++) 
	      {
		cumulative_pages+=pages_in_part[k];
		if(cumulative_pages>number) 
		  break;
	      }
	    cumulative_pages-=pages_in_part[k];
	    part=k-1;
	    
	    page_string = i18n("P.%1 ").arg(number+1-cumulative_pages);
	    
	    part_string = i18n("Sc.%1 ").arg(part+2);
	    
	    part=k;
	    if(pages_in_part[part]==0) 
	      {
		sprintf(page_total_label, i18n("of 1    "));
	      }
	    else if(pages_in_part[part]>0 && pages_in_part[part]<10) 
	      {
		sprintf(page_total_label, i18n("of %d    "), pages_in_part[part]);
	      } 
	    else if (pages_in_part[part]<100) 
	      {
		sprintf(page_total_label, i18n("of %d  "), pages_in_part[part]);
	      }
	    else if (doc) 
	      {
		sprintf(page_total_label, i18n("of %d"), pages_in_part[part]);
	      }
	    else 
	      {
		sprintf(page_total_label, "         ");
	      }
	    
	    sprintf(part_total_label, i18n("of %d  "), num_parts+1);
	  }
	
	part_label_text=operator+(part_string, part_total_label);
	page_label_text=operator+(page_string, page_total_label);
	//position_label=operator+(part_label_text, page_label_text);
      }

  emit newPageShown();
}

void
KGVMiniWidget::set_magstep(unsigned int new_magstep)
{
  magstep = new_magstep;
  if (set_new_magstep())
    {
      page->layout();
      page->resize(page->width(), page->height());
      page->repaint();
      show_page(current_page);
      shrinkWrap();
    }
}

bool
KGVMiniWidget::set_new_magstep()
{
  unsigned int new_magstep;
  bool changed = false;
  float xdpi, ydpi;
  
  new_magstep = magstep;
  
  if (new_magstep != current_magstep)
    {
      //printf("	new_magstep != current_magstep\n");
      page->disableInterpreter();
      changed = true;
      xdpi = default_xdpi;
      ydpi = default_ydpi;
      magnify(&xdpi, new_magstep);
      magnify(&ydpi, new_magstep);
      page->xdpi=xdpi;
      page->ydpi=ydpi;
      current_magstep = new_magstep;
    }
 
  return changed;
}

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));
    }
}

QSize
KGVMiniWidget::sizeHint ()
{
  return QSize (hintwidth, height());
}


void
KGVMiniWidget::showMarkList (bool yes)
{
  if (yes)
    {
      marklist->show();
      scrollBox->show();
      divider->show();
      bshowml = true;
    }
  else
    {
      marklist->hide();
      scrollBox->hide();
      divider->hide();
      bshowml = false;
    }

  redisplay();

  emit markListShown (yes);
}

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

void
KGVMiniWidget::writeSettings()
{
  KConfig *config = kapp->config();
  
  config->setGroup( "KGVMiniWidget" );   

  config->writeEntry ("ShowMarkList", bshowml);
  config->writeEntry ("FancyPageLabels", bfancypagelabels);

  page->writeSettings(); //calls config->sync()

}

bool
KGVMiniWidget::convertFromPDF()
{
  if (!tmppdf.isEmpty())
    unlink (tmppdf);
  
  const char *cmd_convert_pdf = "gs -q -dNODISPLAY -sPSFile=%s -dNOPAUSE  %s -c quit";
  char cmd [2048];
  tmppdf.sprintf ( "%s/kgvtmp_unpdf_%d", _PATH_TMP, getpid());
  sprintf(cmd, cmd_convert_pdf, (const char*)tmppdf, 
	  (const char *)filename);
  
  //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::setOrientation (int o)
{
  orientation = o;
  force_orientation=true;
  if (set_new_orientation (current_page))
    {
      page->layout();
      show_page(current_page);
      shrinkWrap();
    }
}
void
KGVMiniWidget::setSize (int i)
{
  if(doc->epsf && i==1)
    {
      force_pagemedia = false;
      force_document_media = false;
    } 
  else if (i >= base_papersize) 
    {
      default_pagemedia = i;
      force_pagemedia = true;
    } 
  else
    {
      document_media = i;
      force_document_media = true;
    }
  
  if (set_new_pagemedia(current_page))
    {
      page->layout();
      show_page(current_page);
      shrinkWrap();
    }            
}


void
KGVMiniWidget::enableFancyPageLabels (bool e)
{
  bfancypagelabels = e;
  bspecialnoupdate = true; //so we don't redisplay the current page in
                           // pageActivated()
  buildTOC (current_page);
  bspecialnoupdate = false;
}


  
