#ifndef __KMULTIPAGE_H
#define __KMULTIPAGE_H

#include <dcopclient.h>
#include <dcopobject.h>
#include <kparts/part.h>
#include <kparts/browserextension.h>
#include <klibloader.h>
#include <qstringlist.h>
#include <qtimer.h>
#include <qvaluelist.h>

#include "anchor.h"
#include "centeringScrollview.h"
#include "documentPageCache.h"
#include "history.h"
#include "kmultipageInterface.h"
#include "pageSize.h"
#include "selection.h"


class MarkList;
class KConfigDialog;
class QPainter;
class QSplitter;

class documentRenderer;
class documentWidget;
class PageNumber;

// TODO remove virtual inheritance for KDE 4. It's the reason for the strange DCOPObject construction
class KMultiPage : public KParts::ReadOnlyPart, virtual public kmultipageInterface
{
  Q_OBJECT

public:
  KMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name);
  virtual ~KMultiPage();

  /// returns the scrollview used for the display
  virtual CenteringScrollview *scrollView() { return _scrollView; };

  /// Methods which are associated with the DCOP functionality of the
  /// kmultipage. This method returns the file name (not the URL) of
  /// the currently loaded file.
  QString name_of_current_file();

  /// Methods which are associated with the DCOP functionality of the
  /// kmultipage. This method can be implemented by the multipage,
  /// e.g. to jump to a certain location.
  virtual ASYNC  jumpToReference(QString /*reference*/);

  /// Methods which are associated with the DCOP functionality of the
  /// kmultipage. This method checks if a given file is loaded.
  bool   is_file_loaded(QString filename);

  /** The pageCache caches already drawn "documentPages" and invokes
      the renderer if the needed page is not available in the cache. */
  documentPageCache pageCache;

  /** Returns a pointer to the renderer. */
  virtual documentRenderer* getRenderer() const { return renderer; };

// Interface definition start ------------------------------------------------

  /// returns the list of supported file formats. These strings will
  /// be in the format explained in the documentation to
  /// KFileDialog.setFilter(), e.g. ""*.cpp *.cxx *.c++|C++ Source
  /// Files". The use of mimetype-filters is allowed, but
  /// discouraged. Among other penalties, if a multipage gives a
  /// mimetype-filter, e.g. "application/x-dvi", the open file dialog
  /// in kviewshell will not allow the user to see and select
  /// compressed dvi-files.
  virtual QStringList fileFormats() = 0;

  /// opens a file
  virtual bool openFile() = 0;

  /// closes a file
  virtual bool closeURL();

  /// sets a zoom factor. The multipage implementation might refuse to
  /// use a given zoom factor, even if it falls within the bounds given
  /// by the constants MinZoom and MaxZoom which are defined in
  /// zoomlimits.h. In that case, the multipage implementation chooses a
  /// different zomm factor. The implementation returns the factor which
  /// has actually been used. A default implementation is provided.
  virtual double setZoom(double z);

  /// prints
  virtual bool print(const QStringList &pages, int current) = 0;

  /// reads in settings
  virtual void readSettings() {};

  /// writes settings
  virtual void writeSettings() {};

  /// redisplays the contents of the current page
  virtual void redisplay() {} ;

  /// multipage implementations that offer read- and write
  /// functionality should re-implement this method and return true
  /// here.
  virtual bool isReadWrite() {return false;};

  /// multipage implementations that offer read- and write
  /// functionality should re-implement this method.
  virtual bool isModified() {return false;};

  /** Returns the number of the first (i.e. top-left) page in the
      display. Such a number cannot be reasonably assigned
      (e.g. because the current document is empty, or because no
      document has been loaded yet), the method returns "invalid
      page", i.e. 0. */
  virtual PageNumber currentPageNumber();

  virtual Q_UINT16 numberOfPages();

  /** Returns a list with the numbers of the currently selected pages. */
  virtual QValueList<int> selectedPages();

  MarkList* markList() { return _markList; };

  virtual History* history() { return &document_history; };

  /** Use this function to add documenttype specific configuration
      pages. */
  virtual void addConfigDialogs(KConfigDialog* configDialog) { Q_UNUSED(configDialog); };


  /** These methods calculate the Zoomfactor needed to fit the pages
      into the current viewport. Note that the return value need *not*
      be within the limits defined in "zoomLimits.h". If they are not,
      this indicates that fitting to width or height is currently not
      possible (e.g. because no document is loaded). The return value
      should then be ignored and any operation that relies on the
      return value should be aborted. */
  virtual double calculateFitToWidthZoomValue();
  virtual double calculateFitToHeightZoomValue();

  // =========== Interface definition ends

  /** Makes page # pageNr visible, selects the text Elements
      beginSelection-endSelection, and draws the users attention to
      this place with an animated frame  */
  void gotoPage(int pageNr, int beginSelection, int endSelection );
  void gotoPage(const anchor &a);

protected:
  /** Creates new instances of documentWidget. If you need special
      functionality reimplement it in a subclass. This function is
      also the right place to connect to signals emitted by
      documentWidget. */
  virtual documentWidget* createDocumentWidget();

  /** Used to enable/disable KActions of multiPage implementations.
      enableActions(true) should be called whenever a file is
      successfully loaded.  enableActions(false) is called when the
      file is closed. */
  virtual void enableActions(bool) {};

  /** Initializes all data structures that need to know the renderer.
      This function must be called in the constructor of multipage
      implementations. */
  void setRenderer(documentRenderer*);

public slots:
  void doSelectAll();
 
  /** Shows the "text search" dialog, if text search is supported by
      the renderer. Otherwise, the method returns immediately. */
  void showFindTextDialog(void);
 
  /** Starts the text search. The text to search, and the direction in
      which to search is read off the 'findDialog' member, which must
      not be NULL. */
  void  findText(void);

  /** This method may be called after the text search dialog
      'findDialog' has been set up, and the user has entered a search
      phrase. The method searches for the next occurence of the text,
      starting from the beginning of the current page, or after the
      currently selected text, if there is any. */
  void findNextText(void);

  /** This method may be called after the text search dialog
      'findDialog' has been set up, and the user has entered a search
      phrase. The method searches for the next occurence of the text,
      starting from the end of the current page, or before the
      currently selected text, if there is any. */
  void findPrevText(void);

  /** Reloads the file from disk and redisplays. */
  virtual void reload() {};

  virtual void setNumberOfPages(int numberOfPages);

  /** Opens a file requestor and starts a basic copy KIO-Job. A
      multipage implementation that wishes to offer saving in various
      formats must re-implement this slot. */
  virtual void slotSave();

  /** The standard implementation just calls slotSave. */
  virtual void slotSave_defaultFilename();

  /** Empties the page cache and --as the name suggests-- repaints
      all visible widgets. */
  void repaintAllVisibleWidgets();

  /** Tells the multipage if scrollbars should be used. */
  virtual void slotShowScrollbars(bool);

  /** Show or hide the sidebar widget. */
  virtual void slotShowSidebar(bool);

  /** Show or hide thumbnails. */
  virtual void slotShowThumbnails(bool);

  /** Used internally. */
  void slotIOJobFinished ( KIO::Job *job );

  /** Switches to fullscreen mode and back. */
  virtual void slotSetFullPage(bool fullpage);

  virtual void setViewMode(int);

  /** Page Navigation. */
  virtual bool gotoPage(PageNumber page);

  virtual void prevPage();
  virtual void nextPage();
  virtual void firstPage();
  virtual void lastPage();

  virtual void scrollUp();
  virtual void scrollDown();
  virtual void scrollLeft();
  virtual void scrollRight();

  virtual void scrollUpPage();
  virtual void scrollDownPage();
  virtual void scrollLeftPage();
  virtual void scrollRightPage();

  virtual void readUp();
  virtual void readDown();

  virtual void doGoBack();
  virtual void doGoForward();

  /** Scrolls the main scrollview by deltaInPixel (positive values
      scroll DOWN). If the user tries to scroll past the beginning or
      the end of a page, then the method either returns without doing
      anything (if the current page is the first or last page, resp,
      or if the method is called within 200ms after the beg. or end of
      the page was reached), or goes the the next/previous page. The
      delay makes it a little easier for the user to scroll with the
      mouse wheel or the keyboard without involuntarily moving to
      another page. */
  virtual void scroll(Q_INT32 deltaInPixel);

protected slots:
  virtual void goto_page(PageNumber page, int y, bool isLink = true);

  /** Calculates the current page. And calls setCurrentPage() if necessary.
      At the moment the top left visible page is set to the current page. */
 virtual void calculateCurrentPageNumber();

private slots:
 void         handleLocalLink(const QString &linkText);

signals:
  /** Emitted to indicate the number of pages in the file. The
      receiver will set the current page to zero and call the
      gotoPage()-method. */
  void numberOfPages(int nr);

  /** Emitted when a page has been selected in the MarkList. */
  void selected(PageNumber pageNumber);

  /** Emitted to indicate the number of pages in the file and the
      current page. The receiver will not change or update the
      display, nor call the gotoPage()-method. */
  void pageInfo(int nr, int currpg);

  void askingToCheckActions();

  /// emitted when a new preview is available
  void previewChanged(bool previewAvailable);

  void viewModeChanged();

  /** Emitted when the zoom of the pageview changes. */
  void zoomChanged();

// Interface definition end --------------------------------------------------

protected slots:
  virtual void generateDocumentWidgets(PageNumber startPage = PageNumber::invalidPage);

protected:
  enum viewModes {KVS_SinglePage = 0, KVS_Continuous = 1, 
                  KVS_ContinuousFacing = 2, KVS_Overview = 3}; 

  QPtrVector<QWidget> widgetList;

  textSelection userSelection;
  History document_history;

  /** Variable which is used internally by the method
      currentPageNumber() to provide 'lazy' page numbers. */
  PageNumber lastCurrentPage;

private:
  /** Pointer to the text search dialog. This dialog is generally set
      up when the method 'showFindTextDialog(void)' is first
      called. */
  class KEdFind    *findDialog;

  /** Is set by setRenderer. */
  documentRenderer* renderer;

  CenteringScrollview *_scrollView;
  MarkList* _markList;

  QSplitter* mainWidget;

  /** This timer is used to implement a brief delay when the user
      scrolls past the beginning or the end of the page before a the
      program moves to a new page. That way, it is a little easier for
      the user to scroll with the mouse wheel or the keyboard without
      involuntarily moving to another page. The timer is used in the
      scroll() method. */
  QTimer changePageDelayTimer;

  KAction      *copyTextAction;
  KAction      *selectAllAction;
  KAction      *deselectAction;
  KAction      *findTextAction;
  KAction      *findNextTextAction;
  KAction      *findPrevAction;
  KAction      *findNextAction;
};


#endif
