#include <stdlib.h>

#include <qfileinfo.h>
#include <qlayout.h>
#include <qscrollview.h>
#include <qscrollbar.h>
#include <qtimer.h>
#include <qpainter.h>
#include <qprinter.h>
#include <qprintdialog.h>
#include <qobjectlist.h>


#include <kaccel.h>
#include <kdebug.h>
#include <kinstance.h>
#include <klocale.h>
#include <kiconloader.h>
#include <kio/job.h>
#include <kaction.h>
#include <kstdaction.h>
#include <kmessagebox.h>
#include <kglobal.h>
#include <kstandarddirs.h>
#include <kconfig.h>

#include <stdlib.h>
#include <unistd.h>
#include <math.h>

#include "marklist.h"
#include "scrollbox.h"
#include "gotodialog.h"
#include "kpagetest.h"
#include "kviewpart.moc"
#include "pageSizeDialog.h"

extern "C"
{
  void *init_kviewerpart()
  {
    return new KViewPartFactory;
  }
}


KInstance *KViewPartFactory::s_instance = 0L;


KViewPartFactory::KViewPartFactory()
{
}


KViewPartFactory::~KViewPartFactory()
{
  if (s_instance)
    delete s_instance;

  s_instance = 0;
}


KParts::Part *KViewPartFactory::createPartObject( QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const char *, const QStringList &args )
{
  QString partname = "";
  if (args.count() >= 1)
    partname = args[0];
  KParts::Part *obj = new KViewPart(partname, parentWidget, widgetName, parent, name);
  return obj;
}


KInstance *KViewPartFactory::instance()
{
  if (!s_instance)
    s_instance = new KInstance("kviewerpart");
  return s_instance;
}


KViewPart::KViewPart(QString partname, QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name)
  : KViewPart_Iface(parent, name), _partname(partname), _numberOfPages(0),
  _currentPage(0)
{
  pageChangeIsConnected = false;
  setInstance(KViewPartFactory::instance());

  watch = KDirWatch::self();
  connect(watch, SIGNAL(dirty(const QString&)), this, SLOT(fileChanged(const QString&)));
  watch->startScan();

  mainWidget = new QWidget(parentWidget, widgetName);
  mainWidget->setFocusPolicy(QWidget::StrongFocus);
  setWidget(mainWidget);

  QHBoxLayout *hbox = new QHBoxLayout(mainWidget, 0, 0);
  QVBoxLayout *vbox = new QVBoxLayout(hbox);

  scrollBox = new ScrollBox(mainWidget);
  scrollBox->setFixedWidth(75);
  scrollBox->setMinimumHeight(75);
  vbox->addWidget(scrollBox);

  connect(scrollBox, SIGNAL(valueChanged(QPoint)), this, SLOT(scrollBoxChanged(QPoint)));

  markList = new MarkList(mainWidget);
  markList->setAutoUpdate(true);
  vbox->addWidget(markList);
  vbox->setStretchFactor(markList, 1);

  connect(markList, SIGNAL(selected(int)), this, SLOT(pageSelected(int)));

  // create the displaying part

  // Try to load
  KLibFactory *factory;
  factory = KLibLoader::self()->factory(QString("k%1part").arg(_partname).utf8());
  // Support old style parts (as libs)
  if (!factory)
    factory = KLibLoader::self()->factory(QString("libk%1").arg(_partname).utf8());
  if (factory) {
    multiPage = (KMultiPage*) factory->create(mainWidget, QString("k%1").arg(_partname).utf8(), "KPart");
  } else {
    KMessageBox::error(mainWidget, i18n("No module (%1) found").arg(_partname));
    ::exit(-1);
  }
  hbox->addWidget(multiPage->widget());

  // connect to the multi page view
  connect(multiPage, SIGNAL(numberOfPages(int)), this, SLOT(numberOfPages(int)));
  connect(multiPage, SIGNAL(pageInfo(int, int)), this, SLOT(pageInfo(int, int)) );
  connect(multiPage->scrollView(), SIGNAL(contentsMoving(int,int)), this, SLOT(contentsMoving(int,int)));
  multiPage->scrollView()->installEventFilter(this);
  connect( multiPage, SIGNAL( started( KIO::Job * ) ), this, SIGNAL( started( KIO::Job * ) ) );
  connect( multiPage, SIGNAL( completed() ), this, SIGNAL( completed() ) );
  connect( multiPage, SIGNAL( canceled( const QString & ) ), this, SIGNAL( canceled( const QString & ) ) );
  connect( multiPage, SIGNAL( previewChanged(bool)), this, SLOT(updatePreview(bool)));
  connect( multiPage, SIGNAL( setStatusBarText( const QString& ) ), this, SLOT( setStatusBarTextFromMultiPage( const QString& ) ) );

  // settings menu
  showmarklist = new KToggleAction (i18n("Show &Page List"), 0, this, SLOT(slotShowMarkList()), actionCollection(), "show_page_list");
  showPreview = new KToggleAction (i18n("Show P&review"), 0, this, SLOT(slotPreview()), actionCollection(), "show_preview");
  watchAct = new KToggleAction(i18n("&Watch File"), 0, 0, 0, actionCollection(), "watch_file");

  // Orientation menu
  QStringList orientations;
  orientations.append(i18n("Portrait"));
  orientations.append(i18n("Landscape"));
  orientation = new KSelectAction (i18n("&Orientation"), 0, 0, 0, actionCollection(), "view_orientation");
  connect (orientation, SIGNAL(activated (int)), this, SLOT(slotOrientation(int)));
  orientation->setItems(orientations);

  // Zoom Menu
  zoom_action = new KSelectAction (i18n("&Zoom"), 0, 0, 0, actionCollection(), "view_zoom");
  zoom_action->setComboWidth(80);
  zoom_action->setEditable(true);
  zoom_action->setItems(_zoomVal.zoomNames());
  _zoomVal.setZoomValue(1.0); // should not be necessary @@@@
  connect (&_zoomVal, SIGNAL(zoomNamesChanged(const QStringList &)), zoom_action, SLOT(setItems(const QStringList &)));
  connect (&_zoomVal, SIGNAL(valNoChanged(int)), zoom_action, SLOT(setCurrentItem(int)));
  connect (zoom_action, SIGNAL(activated(const QString &)), this, SLOT(setZoomValue(const QString &)));

  // Paper Size Menu
  media = new KSelectAction (i18n("Paper &Size"), 0, 0, 0, actionCollection(), "view_media");
  QStringList items = _paperSize.pageSizeNames();
  items.prepend(i18n("Custom Size..."));
  media->setItems(items);
  connect (media, SIGNAL(activated(int)), this, SLOT(slotMedia(int)));


  zoomInAct = KStdAction::zoomIn (this, SLOT(zoomIn()), actionCollection());
  zoomOutAct = KStdAction::zoomOut(this, SLOT(zoomOut()), actionCollection());

  fitAct = KStdAction::actualSize(this, SLOT(fitSize()), actionCollection());
  fitPageAct = KStdAction::fitToPage(this, SLOT(fitToPage()), actionCollection());
  fitWidthAct = KStdAction::fitToWidth(this, SLOT(fitToWidth()), actionCollection());
  fitHeightAct = KStdAction::fitToHeight(this, SLOT(fitToHeight()), actionCollection());

  // go menu
  backAct = KStdAction::prior(this, SLOT(prevPage()), actionCollection());
  forwardAct = KStdAction::next(this, SLOT(nextPage()), actionCollection());
  startAct = KStdAction::firstPage(this, SLOT(firstPage()), actionCollection());
  endAct = KStdAction::lastPage(this, SLOT(lastPage()), actionCollection());
  gotoAct = KStdAction::gotoPage(this, SLOT(goToPage()), actionCollection());

  readDownAct = new KAction(i18n("Read Down Document"), "next",
			    Key_Space, this, SLOT(readDown() ),
			    actionCollection(), "go_read_down");

  printAction = KStdAction::print(this, SLOT(slotPrint()), actionCollection());
  saveAction = KStdAction::saveAs(multiPage, SLOT(slotSave()), actionCollection());

  // keyboard accelerators
  accel = new KAccel(mainWidget);
  accel->insert(I18N_NOOP("Scroll Up"), Key_Up, this, SLOT(scrollUp()));
  accel->insert(I18N_NOOP("Scroll Down"), Key_Down, this, SLOT(scrollDown()));
  accel->insert(I18N_NOOP("Scroll Left"), Key_Left, this, SLOT(scrollLeft()));
  accel->insert(I18N_NOOP("Scroll Right"), Key_Right, this, SLOT(scrollRight()));

  accel->insert(I18N_NOOP("Scroll Up Page"), SHIFT+Key_Up, this, SLOT(scrollUpPage()));
  accel->insert(I18N_NOOP("Scroll Down Page"), SHIFT+Key_Down, this, SLOT(scrollDownPage()));
  accel->insert(I18N_NOOP("Scroll Left Page"), SHIFT+Key_Left, this, SLOT(scrollLeftPage()));
  accel->insert(I18N_NOOP("Scroll Right Page"), SHIFT+Key_Right, this, SLOT(scrollRightPage()));

  accel->readSettings();

  setXMLFile("kviewerpart.rc");

  m_extension = new KViewPartExtension(this);

  // create the goto dialog
  _gotoDialog = new GotoDialog(mainWidget);
  _gotoDialog->hide();
  connect(_gotoDialog, SIGNAL(gotoPage(const QString&)), this, SLOT(slotGotoDialog(const QString&)));

  // The page size dialog is constructed on first usage -- saves some
  // memory when not used.
  _pageSizeDialog = 0;

  numberOfPages(0);
  checkActions();

  // allow parts to have a GUI, too :-)
  // (will be merged automatically)
  insertChildClient( multiPage );

  readSettings();

  // watch mouse events in the viewport
  QWidget *vp = multiPage->scrollView()->viewport();
  vp->installEventFilter(this);
  // we also have to set an filter on the child
  // TODO: solve this more elegant
  if (vp->children()) {
    QWidget *w = (QWidget*)((QObjectList*)(vp->children()))->first();
    w->installEventFilter(this);
  }
}


KViewPart::~KViewPart()
{
  writeSettings();
  delete multiPage;
}


void KViewPart::setPaperSize(double w, double h)
{
  // reflect in scrollbox
  scrollBox->setMinimumHeight( int(75.0*h/w+0.5));

  // forward
  multiPage->setPaperSize(w, h);

  updateScrollBox();
}


QStringList KViewPart::fileFormats()
{
  return multiPage->fileFormats();
}


void KViewPart::slotShowMarkList()
{
  if (showmarklist->isChecked()) {
    markList->show();
    scrollBox->show();
  } else {
    markList->hide();
    scrollBox->hide();
  }
}


bool KViewPart::openFile()
{
  KURL tmpFileURL;

  // We try to be error-tolerant about filenames. If the user calls us
  // with something like "test", and we are using the DVI-part, we'll
  // also look for "testdvi" and "test.dvi".
  QFileInfo fi(m_file);
  m_file = fi.absFilePath();

  if (fi.exists() == false) {
    // First produce a list of possible endings we try to append to
    // the filename. We decompose the format strings like "*.dvi
    // *.DVI|DVI File" coming from the multipage part.
    QStringList endings;
    QStringList formats = multiPage->fileFormats();
    for ( QStringList::Iterator it = formats.begin(); it != formats.end(); ++it ) {
      QString ending = (*it).simplifyWhiteSpace();
      int bar = ending.find('|');
      if (bar != -1)
	ending = ending.left(bar);

      QStringList localendings = QStringList::split(" ",ending);
      for ( QStringList::Iterator it2 = localendings.begin(); it2 != localendings.end(); ++it2 )
	endings += (*it2).mid(2); // remove "*." of "*.dvi"
    }

    // Now try to append the endings with and without dots, and see if
    // that gives a file.
    for ( QStringList::Iterator it = endings.begin(); it != endings.end(); ++it ) {
      fi.setFile(m_file+(*it));
      if (fi.exists() == true) {
	m_file = m_file+(*it);
	break;
      } else {
	fi.setFile(m_file+"."+(*it));
	if (fi.exists() == true) {
	  m_file = m_file+"."+(*it);
	  break;
	}
      }
    }
    m_url.setPath(QFileInfo(m_file).absFilePath());
  }

  // Now call the openURL-method of the multipage and give it an URL
  // pointing to the downloaded file.
  tmpFileURL.setPath(m_file);
  emit setWindowCaption( tmpFileURL.prettyURL() ); // set Window caption WITHOUT the reference part!
  tmpFileURL.setRef(m_url.ref()); // Pass the reference part of the URL through to the multipage

  bool r = multiPage->openURL(tmpFileURL);

  updateScrollBox();
  markList->select(0);

  if (r) {
    // start viewing horizontally centered
    QScrollView *sv = multiPage->scrollView();
    if (sv)
      sv->center(sv->contentsWidth()/2, 0);

    // Add the file to the watchlist
    watch->addFile( m_file );
  } else {
    m_url = "";
    emit setWindowCaption( "" );
  }

  checkActions();
  return r;
}


void KViewPart::reload(void)
{
  multiPage->reload();
}


void KViewPart::fileChanged(const QString &file)
{
  if (file == m_file && watchAct->isChecked())
    multiPage->reload();
}


bool KViewPart::closeURL()
{
  if( watch && !m_file.isEmpty() )
    watch->removeFile( m_file );

  KParts::ReadOnlyPart::closeURL();

  multiPage->closeURL();

  m_url = "";

  numberOfPages(0);
  checkActions();

  emit setWindowCaption("");

  return true;
}


void KViewPart::slotOrientation(int)
{
  if (orientation->currentItem() == 0)
    setPaperSize( _paperSize.pageWidth_in_mm()/10.0, _paperSize.pageHeight_in_mm()/10.0);
  else
    setPaperSize( _paperSize.pageHeight_in_mm()/10.0, _paperSize.pageWidth_in_mm()/10.0);
  if (_pageSizeDialog != 0)
    _pageSizeDialog->setOrientation(orientation->currentItem());
}


void KViewPart::slotMedia(int id)
{
  if (id > 0) {
    _paperSize.setPageSize(media->currentText());
    slotOrientation(0);
    return;
  }

  // Show the paper size dialog!
  if (_pageSizeDialog == 0) {
    // create the pageSize dialog
    _pageSizeDialog = new pageSizeDialog(mainWidget);
    if (_pageSizeDialog == 0) {
      kdError() << "Could not construct the page size dialog!" << endl;
      return;
    }
    _pageSizeDialog->setOrientation(orientation->currentItem());
    connect(_pageSizeDialog, SIGNAL(sizeSelected(const QString&, int)), this, SLOT(slotSizeSelected(const QString&, int)));
  }

  // Set or update the paper size dialog to show the currently
  // selected value.
  media->setCurrentItem(_paperSize.formatNumber()+1); // Give useful setting in case the user aborts the dialog
  _pageSizeDialog->setPageSize(_paperSize.serialize());
  _pageSizeDialog->show();
}


void KViewPart::slotSizeSelected(const QString &sizeString, int ori)
{
  // Check if there is something to do for us. Speeds up the GUI a
  // lot.
  if ((ori == orientation->currentItem())&&(sizeString == _paperSize.serialize()))
    return;

  orientation->setCurrentItem(ori);
  _paperSize.setPageSize(sizeString);
  // We never select "Custom paper size" so that the user can select
  // it several times in a row.
  if (_paperSize.formatNumber() != -1)
    media->setCurrentItem(_paperSize.formatNumber()+1);
  slotOrientation(0); // Calls setPaperSize() and updates the display.
}


void KViewPart::numberOfPages(int nr)
{
  _numberOfPages = nr;

  markList->clear();

  if (nr == 0) {
    // clear scroll box
    scrollBox->setPageSize(QSize(0,0));
    scrollBox->setViewSize(QSize(0,0));
    _currentPage = 0;
    return;
  }

  for (int i=0; i<nr; i++)
    markList->insertItem(QString("%1").arg(i+1), i);

  setPage(0);
}


void KViewPart::pageInfo(int numpages, int currentpage)
{
  _numberOfPages = numpages;

  markList->clear();

  if (numpages == 0) {
    // clear scroll box
    scrollBox->setPageSize(QSize(0,0));
    scrollBox->setViewSize(QSize(0,0));
    emit pageChanged(QString::null);
    _currentPage = 0;
    return;
  }

  for (int i=0; i<numpages; i++)
    markList->insertItem(QString("%1").arg(i+1), i);

  _currentPage = currentpage;
  // ATTN: The string here must be the same as in setPage() below
  QString pageString = i18n("Page %1 of %2").arg(_currentPage+1).arg(_numberOfPages);
  if (pageChangeIsConnected)
    emit pageChanged(pageString);
  else
    emit setStatusBarText(pageString);

  markList->select(currentpage);
  checkActions();
  updateScrollBox();
}


void KViewPart::setPage(int page)
{
  _currentPage = page;

  QString pageString;
  if (_numberOfPages == 0)
    pageString = QString::null;
  else
    // ATTN: The string here must be the same as in pageInfo(int,int) above
    pageString = i18n("Page %1 of %2").arg(_currentPage+1).arg(_numberOfPages);
  if (pageChangeIsConnected)
    emit pageChanged(pageString);
  else
    emit setStatusBarText(pageString);

  if (!multiPage->gotoPage(page))
    return;

  markList->select(page);

  checkActions();
  updateScrollBox();
}


void KViewPart::prevPage()
{
  if (page() > 0)
    setPage(page()-1);
}


void KViewPart::nextPage()
{
  if (page()+1 < pages())
    setPage(page()+1);
}


void KViewPart::firstPage()
{
  setPage(0);
}


void KViewPart::lastPage()
{
  setPage(pages()-1);
}


void KViewPart::goToPage()
{
  _gotoDialog->show();
}


void KViewPart::slotGotoDialog(const QString &page)
{
  bool ok;
  int p = page.toInt(&ok)-1;
  if (ok && p >= 0 && p < pages())
    setPage(p);
}


void KViewPart::pageSelected(int nr)
{
  // Check beforehand if there is really a new page to display. Often
  // an item in the markList is selected AFTER the page has been set,
  // and then we don't want the mulipage to render twice.
  if (_currentPage == nr)
    return;

  if ((nr >= 0) && (nr<pages()))
    setPage(nr);
}


void KViewPart::zoomIn()
{
  _zoomVal.setZoomValue(multiPage->setZoom(_zoomVal.zoomIn()));
  updateScrollBox();
}


void KViewPart::zoomOut()
{
  _zoomVal.setZoomValue(multiPage->setZoom(_zoomVal.zoomOut()));
  updateScrollBox();
}


void KViewPart::fitToPage()
{
  double w, h;
  float _zoom;

  w = multiPage->zoomForWidth(pageSize().width());
  h = multiPage->zoomForHeight(pageSize().height());

  if (w < h)
    _zoom = w;
  else
    _zoom = h;
  if (_zoom < ZoomLimits::MinZoom/1000.0)
    _zoom = ZoomLimits::MinZoom/1000.0;
  if (_zoom > ZoomLimits::MaxZoom/1000.0)
    _zoom = ZoomLimits::MaxZoom/1000.0;
  _zoomVal.setZoomValue(multiPage->setZoom(_zoom));
  updateScrollBox();
}


void KViewPart::fitSize()
{
  _zoomVal.setZoomValue(multiPage->setZoom(1.0));
  updateScrollBox();
}


void KViewPart::fitToHeight()
{
  // See below, in the documentation of the method "fitToWidth" for an
  // explanation of the complicated calculation we are doing here.
  int targetHeight  = multiPage->scrollView()->viewportSize(0,0).height()-1;
  int targetWidth;
  if (orientation->currentItem() == 0)
    targetWidth = (int)(targetHeight * _paperSize.pageWidth_in_mm()/_paperSize.pageHeight_in_mm() +0.5);
  else
    targetWidth = (int)(targetHeight * _paperSize.pageHeight_in_mm()/_paperSize.pageWidth_in_mm() +0.5);
  targetHeight = multiPage->scrollView()->viewportSize(targetWidth, targetHeight).height()-1;

  float _zoom = multiPage->zoomForHeight(targetHeight);
  if (_zoom < ZoomLimits::MinZoom/1000.0)
    _zoom = ZoomLimits::MinZoom/1000.0;
  if (_zoom > ZoomLimits::MaxZoom/1000.0)
    _zoom = ZoomLimits::MaxZoom/1000.0;
  _zoomVal.setZoomValue(multiPage->setZoom(_zoom));
  updateScrollBox();
}


void KViewPart::fitToWidth()
{
  // There is a slight complication here... if we just take the width
  // of the viewport and scale the contents by a factor x so that it
  // fits the viewport exactly, then, depending on choosen papersize
  // (landscape, etc.), the contents may be higher than the viewport
  // and the QScrollview may or may not insert a scrollbar at the
  // right. If the scrollbar appears, then the usable width of the
  // viewport becomes smaller, and scaling by x does not really fit
  // the (now smaller page) anymore.

  // Caluculate the width and heigt of the view, disregarding the
  // possible complications with scrollbars, e.g. assuming the maximal
  // space is available.
  int targetWidth  = multiPage->scrollView()->viewportSize(0,0).width()-1;
  int targetHeight;
  if (orientation->currentItem() == 0)
    targetHeight = (int)(targetWidth * _paperSize.pageHeight_in_mm()/_paperSize.pageWidth_in_mm() +0.5);
  else
    targetHeight = (int)(targetWidth * _paperSize.pageWidth_in_mm()/_paperSize.pageHeight_in_mm() +0.5);
  // Think again, this time use only the area which is really
  // acessible (which, in case that targetWidth targetHeight don't fit
  // the viewport, is really smaller because of the scrollbars).
  targetWidth      = multiPage->scrollView()->viewportSize(targetWidth, targetHeight).width()-1;

  float _zoom = multiPage->zoomForWidth(targetWidth);
  if (_zoom < ZoomLimits::MinZoom/1000.0)
    _zoom = ZoomLimits::MinZoom/1000.0;
  if (_zoom > ZoomLimits::MaxZoom/1000.0)
    _zoom = ZoomLimits::MaxZoom/1000.0;
  _zoomVal.setZoomValue(multiPage->setZoom(_zoom));
  updateScrollBox();
}


void KViewPart::setZoomValue(const QString &sval)
{
  float fval = _zoomVal.value();
  _zoomVal.setZoomValue(sval);
  if (fval != _zoomVal.value())
    _zoomVal.setZoomValue(multiPage->setZoom(_zoomVal.value()));
  updateScrollBox();
}


QSize KViewPart::pageSize()
{
  QRect r = multiPage->widget()->childrenRect();
  return QSize(r.width(), r.height());
}


void KViewPart::updateScrollBox()
{
  QScrollView *sv = multiPage->scrollView();
  scrollBox->setPageSize(QSize(sv->contentsWidth(), sv->contentsHeight()));
  scrollBox->setViewSize(QSize(sv->visibleWidth(), sv->visibleHeight()));
  scrollBox->setViewPos(QPoint(sv->contentsX(), sv->contentsY()));
  emit zoomChanged(QString("%1%").arg((int)(_zoomVal.value()*100.0+0.5)));
}


void KViewPart::checkActions()
{
  bool doc = !url().isEmpty();

  backAct->setEnabled(doc && page() > 0);
  forwardAct->setEnabled(doc && page()+1 < pages());
  startAct->setEnabled(doc && page() > 0);
  endAct->setEnabled(doc && page()+1 < pages());
  gotoAct->setEnabled(doc && pages()>1);
  readDownAct->setEnabled(doc);

  zoomInAct->setEnabled(doc);
  zoomOutAct->setEnabled(doc);

  fitAct->setEnabled(doc);
  fitPageAct->setEnabled(doc);
  fitHeightAct->setEnabled(doc);
  fitWidthAct->setEnabled(doc);

  media->setEnabled(doc);
  orientation->setEnabled(doc);

  printAction->setEnabled(doc);
  saveAction->setEnabled(doc);
}


void KViewPart::contentsMoving(int x, int y)
{
  QScrollView *sv = multiPage->scrollView();
  scrollBox->setPageSize(QSize(sv->contentsWidth(), sv->contentsHeight()));
  scrollBox->setViewSize(QSize(sv->visibleWidth(), sv->visibleHeight()));
  scrollBox->setViewPos(QPoint(x,y));
}


void KViewPart::scrollBoxChanged(QPoint np)
{
  multiPage->scrollView()->setContentsPos(np.x(), np.y());
}


bool KViewPart::eventFilter(QObject *obj, QEvent *ev)
{
  if (obj == this && ev->type() == QEvent::Resize)
    QTimer::singleShot(0, this, SLOT(updateScrollBox()));

  if (obj != this) {
    if (ev->type() == QEvent::MouseButtonPress) {
      mousePos = ((QMouseEvent*)ev)->globalPos();
      multiPage->scrollView()->setCursor(Qt::sizeAllCursor);
    }

    if (ev->type() == QEvent::MouseMove) {
      QPoint newPos = ((QMouseEvent*)ev)->globalPos();
      if ( ((QMouseEvent*)ev)->state() == LeftButton ) {
	QPoint delta = mousePos - newPos;
	multiPage->scrollView()->scrollBy(delta.x(), delta.y());
      }
      mousePos = newPos;
    }

    if (ev->type() == QEvent::MouseButtonRelease)
      multiPage->scrollView()->setCursor(Qt::arrowCursor);
  }

  return false;
}


void KViewPart::scrollUp()
{
  QScrollBar *sb = multiPage->scrollView()->verticalScrollBar();
  if (sb)
    sb->subtractLine();
  updateScrollBox();
}


void KViewPart::scrollDown()
{
  QScrollBar *sb = multiPage->scrollView()->verticalScrollBar();
  if (sb)
    sb->addLine();
  updateScrollBox();
}


void KViewPart::scrollLeft()
{
  QScrollBar *sb = multiPage->scrollView()->horizontalScrollBar();
  if (sb)
    sb->subtractLine();
  updateScrollBox();
}


void KViewPart::scrollRight()
{
  QScrollBar *sb = multiPage->scrollView()->horizontalScrollBar();
  if (sb)
    sb->addLine();
  updateScrollBox();
}


void KViewPart::scrollUpPage()
{
  QScrollBar *sb = multiPage->scrollView()->verticalScrollBar();
  if (sb)
    sb->subtractPage();
  updateScrollBox();
}


void KViewPart::scrollDownPage()
{
  QScrollBar *sb = multiPage->scrollView()->verticalScrollBar();
  if (sb)
    sb->addPage();
  updateScrollBox();
}


void KViewPart::scrollLeftPage()
{
  QScrollBar *sb = multiPage->scrollView()->horizontalScrollBar();
  if (sb)
    sb->subtractPage();
  updateScrollBox();
}


void KViewPart::scrollRightPage()
{
  QScrollBar *sb = multiPage->scrollView()->horizontalScrollBar();
  if (sb)
    sb->addPage();
  updateScrollBox();
}


void KViewPart::scrollTo(int x, int y)
{
  QScrollView *sv = multiPage->scrollView();
  sv->setContentsPos(x, y);
  updateScrollBox();
}


void KViewPart::updatePreview(bool avail)
{
  QString size = _paperSize.serialize()+"/";
  if (orientation->currentItem() == 0)
    size += i18n("portrait");
  else
    size += i18n("landscape");
  emit sizeChanged(size);


  QPixmap pixmap(scrollBox->width(), scrollBox->height());
  QPainter p(&pixmap);

  if (showPreview->isChecked() && avail
      && multiPage->preview(&p, scrollBox->width(), scrollBox->height()))
    scrollBox->setBackgroundPixmap(pixmap);
  else
    scrollBox->setBackgroundMode(QFrame::PaletteMid);
}


void KViewPart::slotPreview()
{
  updatePreview(true);
}


void KViewPart::slotPrint()
{
  QStringList pages;
  QValueList<int> selectedPageNo = markList->markList();

  QValueList<int>::iterator it;
  for ( it = selectedPageNo.begin(); it != selectedPageNo.end(); ++it )
    pages.append(QString::number((*it)-1));

  multiPage->print(pages, page());
}


void KViewPart::readSettings()
{
  KConfig *config = instance()->config();

  config->setGroup("GUI");

  showmarklist->setChecked(config->readBoolEntry("PageMarks", true));
  slotShowMarkList();

  watchAct->setChecked(config->readBoolEntry("WatchFile", true));
  showPreview->setChecked(config->readBoolEntry("ShowPreview", true));
  float _zoom = config->readDoubleNumEntry("Zoom", 1.0);
  if ( (_zoom < ZoomLimits::MinZoom/1000.0) || (_zoom > ZoomLimits::MaxZoom/1000.0))
    _zoom = 1.0;
  _zoomVal.setZoomValue(multiPage->setZoom(_zoom));

  // Read Paper Size and orientation
  int orient = config->readNumEntry("Orientation", 0 );
  orientation->setCurrentItem(orient);
  if (_pageSizeDialog != 0)
    _pageSizeDialog->setOrientation(orient);

  _paperSize.setPageSize(config->readEntry("PaperFormat", QString::null));
  // Since "Custom paper size" is the first entry in the media list,
  // we can just add 1 to the formatNumber. We never select "Custom
  // paper size" so that the user can select it several times in a row.
  if (_paperSize.formatNumber() == -1)
    media->setCurrentItem(-1); // Nothing selected
  else
    media->setCurrentItem(_paperSize.formatNumber()+1);
  slotOrientation(0); // Apply orientation and paperSize settings.
}


void KViewPart::writeSettings()
{
  KConfig *config = instance()->config();

  config->setGroup("GUI");

  config->writeEntry("PageMarks", showmarklist->isChecked());
  config->writeEntry("WatchFile", watchAct->isChecked());
  config->writeEntry("ShowPreview", showPreview->isChecked());
  config->writeEntry("Zoom", _zoomVal.value());

  config->writeEntry("Orientation", orientation->currentItem() );
  config->writeEntry("PaperFormat", _paperSize.serialize() );
  config->sync();
}


void KViewPart::readDown()
{
  QScrollBar *sb = multiPage->scrollView()->verticalScrollBar();
  if (sb) {
    if (sb->value() == sb->maxValue()) {
      nextPage();
      QScrollView *sv = multiPage->scrollView();
      scrollTo(sv->contentsX(), 0);
    } else
      sb->addPage();
  }
}


void KViewPart::connectNotify ( const char *sig )
{
  if (QString("2pageChanged(const QString&)") == sig)
    pageChangeIsConnected = true;
}


void KViewPart::setStatusBarTextFromMultiPage( const QString &msg )
{
  if (msg.isEmpty()) {
    if (pageChangeIsConnected)
      emit setStatusBarText(QString::null);
    else
      emit setStatusBarText(i18n("Page %1 of %2").arg(_currentPage+1).arg(_numberOfPages));
  }
  else
    emit setStatusBarText(msg);
}


KViewPartExtension::KViewPartExtension(KViewPart *parent)
  : KParts::BrowserExtension( parent, "KViewPartExtension")
{
}
