You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdegraphics/kviewshell/documentRenderer.h

479 lines
18 KiB

// -*- C++ -*-
//
// Class: documentRenderer
//
// Abstract class for rendering document types. Needs to be
// subclassed by the actual parts using kviewshell. Part of
// KViewshell - A generic interface for document viewers.
//
// (C) 2004-2005 Wilfried Huss, Stefan Kebekus. Distributed under the GPL.
//
#ifndef DOCUMENTRENDERER_H
#define DOCUMENTRENDERER_H
#include "bookmark.h"
#include "pageNumber.h"
#include "pageSize.h"
#include <qguardedptr.h>
#include <qcolor.h>
#include <qmutex.h>
#include <qobject.h>
#include <qvaluevector.h>
class Anchor;
class KURL;
class RenderedDocumentPage;
/** \brief loads and renders documents
This abstract class is one of the two core classes that must be
implemented by all authors who write plugins for the kviewshell
programm. It is responsible for document loading and rendering. As a
minimum, the setFile() and drawPage() must be reimplemented.
This documentation mentiones only the methods and members that are
important for authors of plugins. For full documentation, consult the
header file documentRenderer.h.
@warning Future versions of kviewshell will use threading to keep the
GUI responsive while pages are rendered. As a result, IT IS ABSOLUTELY
NECESSARY that your implementation is THREAD-SAFE, if not, this can
result in infrequent and very hard-to-find crashes of your
programm. Use the member mutex to make your implemetation
thread-safe.
@author Wilfried Huss, Stefan Kebekus
*/
class DocumentRenderer : public QObject
{
Q_OBJECT
public:
/** \brief default constructor */
DocumentRenderer(QWidget* parent);
virtual ~DocumentRenderer();
/** \brief loading of files
This is a purely virtual method that 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.
- return 'true' on success and 'false' on failure. Before 'false' is
returned, the method clear() should be called
When the method returns 'true', it is expected that
- the member _isModified is set to 'false'
- 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,
or if your document doesn't contain any.
- the list 'bookmarks' is filled with data; it is perfectly fine to
leave this list empty, if your file format does not support
bookmarks or if your document doesn't contain any.
- the method drawPage() works
@note It is perfectly possible that setFile() is called several
times in a row, with the same or with different filenames.
@warning The signal documentIsChanged() must not be emitted while
the method runs.
@warning Future versions of kviewshell will use threading to keep
the GUI responsive while pages are rendered. As a result, IT IS
ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
not, this can result in infrequent and very hard-to-find crashes of
your programm. Use the member mutex to make your implemetation
thread-safe.
@param fname name of the file to open. It is not guaranteed that the
file exists, that it is a file, or that it is readable.
@param base original URL of the file that was opened.
If the program that uses this documentRenderer was asked to open
http://www.kde.org/test.dvi.bz2, then the program would download the
file to a temporary file and decompress it, generating
e.g. /tmp/tmp.dvi. In that case, base would be
http://www.kde.org/test.dvi.bz2, and fname=/tmp/tmp.dvi. The base
can be used by the documentRenderer to handle relative URLs that
might be contained in a file. Otherwise, it can safely be ignored.
@returns '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
*/
virtual bool setFile(const QString &fname, const KURL &base) = 0;
/** \brief clearing the document renderer
This method clears the renderer, so that it represents an empty
document. The standard implementation doe the following:
- sets 'numPages' to zero
- clears the pageSizes and the anchorList
- sets _isModified to 'false'
Most authors of kviewshell-plugins will probably want to
re-implement this to clear internal data structures of their
implementations.
@warning Future versions of kviewshell will use threading to keep
the GUI responsive while pages are rendered. As a result, IT IS
ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
not, this can result in infrequent and very hard-to-find crashes of
your programm. Use the member mutex to make your implemetation
thread-safe.
*/
virtual void clear();
/* Returns true if the current document contains 0 pages. */
bool isEmpty() const {return numPages == 0;}
/* Tells if the document was modified after is was loaded. */
bool isModified() const {return _isModified; }
/* 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() const {return numPages; }
QPtrList<Bookmark> getBookmarks() const { return bookmarks; }
/* Returns the size of page 'page'. If the document is empty, if the
page specified is not a page of the document or 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(const PageNumber& page);
/* 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();}
/** rendering of documents
This purely virtual method is the most important method in the
DocumentRenderer class. It must be re-implemented by authors who
want to write plugins for the kviewshell program. The purpose of
this method is to render a graphical representation into a
documentPage structure. More specifically, the implementation needs
to
- call the documentPage::clear() on *page
and the do all of the following, in no particular order
- obtain the pointer to the QPaintDevice from the documentPage using
the documentPage::getPaintDevice() method and draw a graphical
representation of the page number page->getPageNumber() into the
QPaintDevice, using the given resolution. If the member
accessibilityBackground is true, the accessibilityBackgroundColor
should be used for a background color, if possible. Otherwise,
white should be used, if possible. If you need to compute the size
of the page in pixel, do this as follows:
@code
SimplePageSize psize = pageSizes[page->getPageNumber() - 1];
if (psize.isValid()) {
int width_in_pixel = resolution * psize.width().getLength_in_inch();
int height_in_pixel = resolution * psize.height().getLength_in_inch();
<...>
}
@endcode
Don't use page->height() or page->width() to calculate the sizes
---KViewShell uses transformations e.g. to rotate the page, and
sets the argument 'resolution' accordingly; these changes are not
reflected in page->height() and page->width(). Similar problems
occur if KViewShell required a shrunken version of the page,
e.g. to print multiple pages on one sheet of paper.
- if your document contains hyperlinks, fill the
documentPage::hyperLinkList with HyperLinks, using pixel
coordinates for the coordinates in the Hyperlink::box member of
the Hyperlink. The Hyperlink::baseline member of the Hyperlink
can be ignored. The linkText member of the Hyperlink should either
be an absolute URL ("http://www.kde.org"), or be of the form
"#anch", where the string "anch" is contained in the anchorList.
- if your plugin supports full-text information, fill
documentPage::textLinkList with HyperLinks, using pixel
coordinates for the coordinates in the Hyperlink::box and
Hyperlink::baseline members of the Hyperlink. The entries in the
documentPage::textLinkList should have a natural ordering, "first
text first" (left-to-right, up-to-down for western languages,
right-to-left for hebrew, etc.). This is important so that text
selection with the mouse works properly, and only continuous
blocks of text can be selected.
@note 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.
@note If your plugin supports full-text information, you probably
want to re-implement the method supportsTextSearch() below.
@warning As mentioned above, it may be tempting to compute the image
size in pixel, using page->height() and page->width(). DON'T DO
THAT. KViewShell uses transformations e.g. to rotate the page, and
sets the argument 'resolution' accordingly; these changes are not
reflected in page->height() and page->width(). Similar problems
occur if KViewShell required a shrunken version of the page, e.g. to
print multiple pages on one sheet of paper.
@warning The signal documentIsChanged() must not be emitted while the
method runs.
@warning Future versions of kviewshell will use threading to keep
the GUI responsive while pages are rendered. As a result, IT IS
ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
not, this can result in infrequent and very hard-to-find crashes of
your programm. Use the member mutex to make your implemetation
thread-safe.
@param resolution this argument 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.
@param page pointer to a documentPage structure that this method
rendered into.
*/
virtual void drawPage(double resolution, RenderedDocumentPage* page) = 0;
/** rendering of documents at thumbnail size
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.
@warning Future versions of kviewshell will use threading to keep
the GUI responsive while pages are rendered. As a result, IT IS
ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
not, this can result in infrequent and very hard-to-find crashes of
your programm. Use the member mutex to make your implemetation
thread-safe.
*/
virtual void drawThumbnail(double resolution, RenderedDocumentPage* page);
/** quick extraction of text information
This method returns the textinformation of the current page if available.
It is only called when the page pixmap is not of interest, so it is possible
to implement it much more efficiently then the drawPage() method.
The default implementation just calls drawPage().
@warning Future versions of kviewshell will use threading to keep
the GUI responsive while pages are rendered. As a result, IT IS
ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
not, this can result in infrequent and very hard-to-find crashes of
your programm. Use the member mutex to make your implemetation
thread-safe.
@param page pointer to a documentPage structure that this method rendered into.
*/
virtual void getText(RenderedDocumentPage* page);
/** Flag to indicate if full text is supported
If your implementation of the drawPage() method supports full-text
information and writes to the documentPage::textLinkList, this
method should be re-implemented to return 'true'. The text-search
and text-selection utilities will then be enabled in the GUI.
The default implementation returns 'false'.
*/
virtual bool supportsTextSearch() const {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 &);
/* Quick file validity check
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. If
such considerations are not an issue for you, this method does not
need to be re-implemented.
@warning Future versions of kviewshell will use threading to keep
the GUI responsive while pages are rendered. As a result, IT IS
ABSOLUTELY NECESSARY that your implementation is THREAD-SAFE, if
not, this can result in infrequent and very hard-to-find crashes of
your programm. Use the member mutex to make your implemetation
thread-safe.
@param fileName name of the file that should be checked for validity
@returns 'false' if the file 'fileName' is obviously invalid, and
true otherwise. The default implementation always returns
'true'.
*/
virtual bool isValidFile(const QString& fileName) const;
void setAccessibleBackground(bool accessibleMode, const QColor& background = QColor(255, 255, 255));
signals:
/** signals that the document is changed
This signal can be emitted if the document or status of this class
changed internally so that all associated widgets should be
repainted. This could be emitted, e.g. if pages are removed from a
document, or if some preferences change that have some direct
influence on the way the document is rendered.
When this signal is emitted, the whole GUI setup is re-computed, and
all widgets are re-drawn. This can take considerable time.
*/
void documentIsChanged();
/** sets text in the statusbar
This signal is emitted when the renderer needs to inform the user
via the status bar. Since the status bar is not always visible, and
since the duration that the message is shown is not quite specified,
this should not be used for important information. */
void setStatusBarText( const QString& );
protected:
/** mutex used to make method thread-safe
This is a recursive mutex that must be used to make the public
methods of this class thread-safe. Future versions of kviewshell
will use threading to keep the GUI responsive while pages are
rendered. As a result, IT IS ABSOLUTELY NECESSARY that your
implementation is THREAD-SAFE, if not, this can result in infrequent
and very hard-to-find crashes of your programm.
*/
QMutex mutex;
/** number of pages in the document
This member is set by the implementations of the setFile()
method. It is set to zero by the constructor and in clear().
@warning Only the constructor and the methods setFile() and clear()
may write to this member.
*/
Q_UINT16 numPages;
/** page sizes
This vector contains the size of every page in the document. 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.
@warning Only the constructor and the methods setFile() and clear()
may write to this member.
*/
QValueVector<SimplePageSize> pageSizes;
/** bookmarks
This (ordered!) list contains the bookmarks that are contained in
the document. The values in this vector are set by the setFile()
method, and cleared by the constructor and the clear() method.
@warning Only the constructor and the methods setFile() and clear()
may write to this member.
*/
QPtrList<Bookmark> bookmarks;
/** map of anchors in a document.
This map contains the anchors that are contained in the
document. The values in this map are set by the setFile() method,
and cleared by the constructor and the clear() method.
@warning Only the constructor and the methods setFile() and clear()
may write to this member.
*/
QMap<QString, Anchor> anchorList;
/** pointer to the parent widget
This pointer can be used by implementations e.g. to display error
messages. This pointer can well be zero.
*/
QGuardedPtr<QWidget> parentWidget;
/** specifies if accessibilityBackgroundColor should be used
If true, the drawPage() and drawThumbnail() methods should use
accessibilityBackgroundColor as the backgroundcolor of the
pages.
*/
bool accessibilityBackground;
/** background color, to be used for visibly impaired users
If accessibilityBackground is true, the drawPage() and
drawThumbnail() methods should use this color as the backgroundcolor
of the pages.
*/
QColor accessibilityBackgroundColor;
/** Flag if document is modified
This flag indicates if the document was modified after it was
loaded. It is set to 'false' in the constructor, in the clear() and
setFile() method. It can be set to 'true' be methods that modify the
document (e.g. the deletePages() method of the djvu implementation
of this class).
*/
bool _isModified;
};
#endif