summaryrefslogtreecommitdiffstats
path: root/kviewshell/documentRenderer.h
blob: 82d2085efda8a7da8f91bd9f37786f4ed941e15e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
// -*- 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 <tqguardedptr.h>
#include <tqcolor.h>
#include <tqmutex.h>
#include <tqobject.h>
#include <tqvaluevector.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 TQObject
{
  Q_OBJECT
  TQ_OBJECT

public:
  /** \brief default constructor */
  DocumentRenderer(TQWidget* 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 TQString &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; }

  TQPtrList<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 TQPaintDevice from the documentPage using
    the documentPage::getPaintDevice() method and draw a graphical
    representation of the page number page->getPageNumber() into the
    TQPaintDevice, 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 TQString &reference);
  
  /* Looks up a anchor in the "anchorList". Returns the anchor found,
     or an invalid anchor otherwise. 
  */
  Anchor findAnchor(const TQString &);
  
  /* 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 TQString& fileName) const;

  void setAccessibleBackground(bool accessibleMode, const TQColor& background = TQColor(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 TQString& );

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.
  */
  TQMutex 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.
  */
  TQ_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.
  */
  TQValueVector<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.
  */
  TQPtrList<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.
  */
  TQMap<TQString, 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.
  */
  TQGuardedPtr<TQWidget> 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.
  */
  TQColor 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