diff options
Diffstat (limited to 'kviewshell/documentRenderer.h')
-rw-r--r-- | kviewshell/documentRenderer.h | 478 |
1 files changed, 478 insertions, 0 deletions
diff --git a/kviewshell/documentRenderer.h b/kviewshell/documentRenderer.h new file mode 100644 index 00000000..a8a87410 --- /dev/null +++ b/kviewshell/documentRenderer.h @@ -0,0 +1,478 @@ +// -*- 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 |