//
// Class: documentRenderer
//
// Abstract class for displaying document types.  Needs to be
// subclassed by the actual parts using kviewshell.  Part of
// KViewshell - A generic interface for document viewers.
//
// (C) 2004 Wilfried Huss, Stefan Kebekus. Distributed under the GPL.
//

#ifndef __DOCUMENTRENDERER_H__
#define __DOCUMENTRENDERER_H__

#include <qguardedptr.h>
#include <qobject.h>
#include <qvaluevector.h>

#include "anchor.h"
#include "pageNumber.h"
#include "pageSize.h"

class documentPage;

class documentRenderer : public QObject
{
  Q_OBJECT

public:
  /** Constructs a documentRenderer. The parent widget is used by
      implementations e.g. to display error dialogs. The parent widget
      may be destroyed before the documentRenderer. */
  documentRenderer(QWidget* parent);

  virtual ~documentRenderer();

  /** This method must be re-implemented. It is called when a file
      should be loaded. The implementation must then do the following

      - initialize internal data structures so the document pointed to
        by 'fname' can be rendered quickly. It is not necessary
        actually load the file; if the implementation choses to load
        only parts of a large file and leave the rest on the disc,
        this is perfectly fine. The signal needsRepainting() should
        not be emitted while the method runs.

      - return 'true' on success and 'false' on failure. Even after
        this method returns 'false' the class must act reasonably,
        i.e. by clear()ing the document

      After the method returns 'true', it is expected that

      - the member 'numPages' is either set to 0 if the document is
        empty, or else to the number of page in the document

      - the vector pageSizes *must* either be empty (e.g. if your file
        format does not specify a page size), or must be of size
        totalPages(), and contain the sizes of all pages in the
        document.

      - the anchorList is filled with data (it is perfectly fine to
        leave the anchorList empty, if your file format does not
        support anchors)

      - the method drawPage() works

      Note that it is perfectly possible that setFile(..) is called
      several times in a row, with the same or with different
      filenames.
  */
  virtual bool setFile(const QString &fname) = 0;

  /** This method clears the renderer, i.e. it

  - sets 'numPages' to zero

  - clears the pageSizes and the anchorList

  Most implementations of documentRenderer will probably want to
  re-implement this. */
  virtual void clear();

  /** Returns true if the current document contains 0 pages. */
  bool isEmpty() const {return numPages == 0;};

  /** Returns the number of pages in the document. This method can
      well return 0, e.g. if no document has been loaded yet, or if
      the current document is empty. */
  PageNumber totalPages(void) const {return numPages; };

  /** Returns the size of page 'page'. If the document does not
      specify a size (which happens, e.g., for some DVI-files), then
      an invalid page size is returned. */
  simplePageSize sizeOfPage(PageNumber page) const;

  /** Returns true if the document specifies page sizes, and false
      otherwise. NOTE: the information returned by this method is not
      always 100% reliable. Although unlikely, it is theoretically
      possible that this method returns 'true', but still some of the
      sizes returned by sizeOfPage() are invalid. */
  bool hasSpecifiedPageSizes() const {return !pageSizes.isEmpty();}

  /** This is the most important method in the documentRenderer
      class. <Pending: further explanation>. Note that this method is
      often called in a paintEvent, so that care must be taken to
      return as soon as possible. No user interaction should be done
      during the execution. The argument 'resolution' contains the
      resolution of the display device. In principle. In fact,
      kviewshell implements zooming by using values that are not
      exactly the resolution of the display, but multiplied with the
      zoom factor. Bottom line: the documentRenderer should act as if
      this field indeed contains resolution of the display device. */
  virtual void drawPage(double resolution, documentPage* page) = 0;

  /** This method is used to draw thumbnails. The standared
      implementations just calls 'drawPage' to do the job.
      Reimplement this if the used fileformat has embedded
      Thumbnails. */
  virtual void drawThumbnail(double resolution, documentPage* page);

  /** @@@ */
  virtual bool supportsTextSearch(void) {return false;};

  /** This method will try to parse the reference part of the DVI
      file's URL, (either a number, which is supposed to be a page
      number, or src:<line><filename>) and see if a corresponding
      section of the DVI file can be found. If so, it returns an
      anchor to that section. If not, it returns an invalid anchor. */
  virtual anchor        parseReference(const QString &reference);

  /** Looks up a anchor in the "anchorList". Returns the anchor found,
      or an invalid anchor otherwise. */
  anchor findAnchor(const QString &);

  /** Returns 'false' if the file 'fileName' is obviously invalid, and
      true otherwise. The default implementation always returns
      'true'. This method is used internally, to check if a file is
      valid before it is re-loaded. This is used e.g. by kdvi: when a
      the user TeXes a file, the file changes immediately. If the
      'watch file' option is set, kdvi is informed immediately. At
      that time, however, the TeX typesetting program still writes to
      the dvi file, and reloading must be postphoned till TeX
      finishes, and the dvi file becomes vaild. */
  virtual bool isValidFile(const QString fileName);

signals:
  /** Emitted if the status of this class changed internally so that
      all associated widgets should be repainted. This could be
      emitted, e.g. if some preferences change that have some direct
      influence on the way the document is rendered. */
  void needsRepainting();

protected:
  /** Number of pages in the document. Set by the implementations of
      the setFile(..) method, and set to zero by the constructor and
      in clear(). */
  Q_UINT16  numPages;

  /** This vector contains the size of every page in the file. To
      accomodate for file format that do not specify a page size, it
      is explicitly allowed that this vector is empty, or that entries
      are invalid page sizes. The values in this vector are set by the
      setFile(...) method.

      Note: if the document does not specify page sizes, this vector
      should --for performance reasons-- be empty, and not set to a
      large number of invalid page sizes.
  */
  QValueVector<simplePageSize> pageSizes;

  /** List of anchors in a document. */
  QMap<QString, anchor> anchorList;

  /** Pointer to the parent widget. This pointer can be used by
      implementations e.g. to display error messages. */
  QGuardedPtr<QWidget> parentWidget;
};

#endif
