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
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
|
// -*- C++ -*-
#ifndef _KMULTIPAGE_H
#define _KMULTIPAGE_H
#include "pageView.h"
#include "documentPageCache.h"
#include "documentRenderer.h"
#include "history.h"
#include "kmultipageInterface.h"
#include "marklist.h"
#include <kparts/part.h>
#include <tqtimer.h>
class Anchor;
class DocumentWidget;
class KConfigDialog;
class KPrintDialogPage_PageOptions;
class KPrinter;
class PageView;
class TQPainter;
class TQSplitter;
class TQToolBox;
class simplePageSize;
class TableOfContents;
class PageNumber;
class SearchWidget;
/** \brief This class provides plugin-specific GUI elements for kviewshell plugins
@author Wilfried Huss, Stefan Kebekus
*/
// 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(TQWidget *parentWidget, const char *widgetName, TQObject *parent, const char *name);
virtual ~KMultiPage();
/* returns the scrollview used for the display */
virtual TQWidget* mainWidget() {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. */
TQString 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(const TQString& /*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(const TQString& filename);
/* Opens file and sets URL
This method does the same as openFile, but sets the m_url of the
kmultipage. This can be important, for the following reason:
assume that a DVI is or DJVU-file is located on a web server at
baseURL=http://www.x.x/x.dvi The file may refer to external
graphic files using relative links.
The file is downloaded by the kviewpart to a temporary file on
the hard disk, say /tmp/t.dvi. The kviewpart would then call this
method with filename=/tmp/t.dvi and baseURL=http://www.x.x/x.dvi,
so the DVI-renderer knows to interpret the link to t.jpg as
http://www.x.x/t.jpg, and will download the file from there.
@warning This method is virtual only for technical reasons. Do
not re-implement this method
@returns true on success, false on failure
*/
virtual bool openURL(const TQString &filename, const KURL &base_url);
/** Prints a document
This method prints a document. The default implementation offers
fairly good printer support, but printing with the default
implementation is usually quite slow as tremendous amounts of data
needs to be transferred to the printer. To limit the data sent to
the printer, this default implementation prints only at low
resolution and produces mediocre quality. This method can (and
should) therefore be re-implemented if you have good code to convert
your document to PostScript.
Example: If your document consists of a single A4 page that contains
a DJVU image of 30KB, then the default implementation would render
the image in 600dpi, i.e. in about 7000x5000 pixel, and then send
this huge graphics uncompressed to the printer. A smart
implementation, on the other hand, would send the DJVU-file directly
to the printer, together with a DJVU decoder, which is implemented
in PostScript and uses only a few KB of memory, making for less than
40KB of data sent to the printer.
If you decide to re-implement this method, you need to decide if
your implementation will support the options offered by the "page
size & placement" tab of the print dialog. If these options are set,
pages that are smaller/larger than the printer's paper size will be
shrunk/enlarged and optionally centered on the paper.
If your implementation does not support the options, the following
code should be used:
@code
// Obtain a fully initialized KPrinter structure, and disable all
// entries in the "Page Size & Placement" tab of the printer dialog.
KPrinter *printer = getPrinter(false);
// Abort with an error message if no KPrinter could be initialized
if (printer == 0) {
kdError(4300) << "KPrinter not available" << endl;
return;
}
// Show the printer options dialog. Return immediately if the user
// aborts.
if (!printer->setup(parentWdg, i18n("Print %1").arg(m_file.section('/', -1)) )) {
delete printer;
return;
}
... <Produce a PostScript file, with filename, say, tmpPSFile. You
can use all the features that KPrinter has to offer. Note that
printer->pageList() gives a list of pages to be printed, where "1"
denotes the first page, "2" the second, etc.> ...
printer->printFiles( TQStringList(tmpPSFile), true );
delete printer;
@endcode
If your implementation does support the options, code must be
provided to support the KPrinter options
"kde-kviewshell-shrinkpage", "kde-kviewshell-expandpage",
"kde-kviewshell-centerpage" and "kde-kviewshell-rotatepage". It is
important to note that "kde-kviewshell-rotatepage" and
"kde-kviewshell-centerpage" should by default treated as "true",
while the other options should be "false" by default. The following
code sees to that:
@code
// Obtain a fully initialized KPrinter structure, and enable all
// entries in the "Page Size & Placement" tab of the printer dialog.
KPrinter *printer = getPrinter(true);
// Abort with an error message if no KPrinter could be initialized
if (printer == 0) {
kdError(4300) << "KPrinter not available" << endl;
return;
}
// Show the printer options dialog. Return immediately if the user
// aborts.
if (!printer->setup(parentWdg, i18n("Print %1").arg(m_file.section('/', -1)) )) {
delete printer;
return;
}
if (printer->option( "kde-kviewshell-shrinkpage" ) == "true")
<Shrink some pages to paper size, where necessary>
if (printer->option( "kde-kviewshell-expandpage" ) == "true")
<Expand some pages to paper size, where necessary>
if (printer->option( "kde-kviewshell-centerpage" ) != "false")
<Center pages on paper>
if (printer->option( "kde-kviewshell-rotatepage" ) != "false")
<rotate pages by 90 deg. counterclockwise, if paper orientation is different from pages orientation>
... <Produce a PostScript file, with filename, say, tmpPSFile. You
can use all the features that KPrinter has to offer. Note that
printer->pageList() gives a list of pages to be printed, where "1"
denotes the first page, "2" the second, etc.> ...
printer->printFiles( TQStringList(tmpPSFile), true );
delete printer;
@endcode
For more information, see the default implementation in the source
file kmultipage.cpp. You might also look at the documentation to
getPrinter().
*/
virtual void print();
/* 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. */
virtual bool hasSpecifiedPageSizes() const {return renderer && renderer->hasSpecifiedPageSizes();}
/* This methos is similar to openFile(). It is used when the "Watch
file" option is activated, and the file has changed on disk. It
differs from openFile() in two aspects: first, the file is
checked for validity with DVIRenderer.isValidFile(m_file) if the
file is invalid, a timer event is used to call the method again
after a brief pause. Secondly, when the GUI is updated, the
implementation does not jump to the first page, but tries to keep
the current page. */
virtual void reload();
// Interface definition start ------------------------------------------------
/** list of supported file formats, for saving
This member must return the list of supported file formats for
saving. These strings returned must 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 TQStringList fileFormats() const = 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);
/** reads in settings. Reimplementations must call this. */
virtual void readSettings();
/** writes settings. Reimplementations must call this. */
virtual void writeSettings();
/** Flag to indicate that this implementation has support for textserach and selection */
virtual bool supportsTextSearch() const { return getRenderer() && getRenderer()->supportsTextSearch(); }
/** Flag to indicate the document was modified since last saved
KMultiPage implementations that offer functionality that
modifies the document (e.g. remove or insert pages) must
re-implement this method to return
@returns 'true' if the document was modified since it was last
saved
*/
virtual bool isModified() const {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();
/* Returns the number of pages in the currently loaded document or
0, if no document is loaded or if the document is empty */
PageNumber numberOfPages() const {return renderer.isNull() ? (PageNumber)0 : renderer->totalPages();}
/* List of pages selected in the sidebar
@returns a list with the numbers of the currently selected
pages. */
virtual TQValueList<int> selectedPages() {return markList()->selectedPages();}
virtual History* history() { return &document_history; }
/** Add pages to the KViewshell's central preferences dialog
This method can be re-implemented to add documenttype specific
configuration pages to the central preferences dialog. The
documentation to KConfigDialog explains how to do that.
The default implementation does nothing.
@param configDialog a pointer to the KConfigDialog the dialog to
add pages to
*/
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();
/* Returns the number of columns into which the widgets are aligned. */
virtual Q_UINT8 getNrColumns() const { return _scrollView->getNrColumns(); }
virtual Q_UINT8 getNrRows() const { return _scrollView->getNrRows(); }
virtual bool overviewMode() const { return _scrollView->overviewMode(); }
// =========== Interface definition ends
/* ---------------------------------------------------------------------
The following methods export functions of the DocumentPageCache which
are currently needed by KViewPart. TODO: Clean this up again without
directly linking DocumentPageCache to the KViewPart. */
/* Returns the size of page 'page'. If the document does not
specify a size (which happens, e.g., for some DVI-files), then
the userPreferredSize is returned. */
virtual SimplePageSize sizeOfPage(const PageNumber& page = 1) const { return pageCache->sizeOfPage(page); }
public slots:
/* Sets the userPreferredSize, which is explained below */
virtual void setUserPreferredSize(const SimplePageSize& t) { pageCache->setUserPreferredSize(t); }
virtual void setUseDocumentSpecifiedSize(bool b) { pageCache->setUseDocumentSpecifiedSize(b); }
// --------------------------------------------------------------------
protected:
/** Update GUI after loading or closing of a file
This method is called by openFile() when a new file was loaded,
and by closeURL() when a file is closed so that the kmultipage
implementation can update its own GUI, enable/disable actions,
prepare info texts, etc. At the time the method is executed, the
file has already been loaded into the renderer using
renderer.setFile(), or closed using renderer.clear() and the
standard KMultiPage GUI is set up. The filename can be accessed
via m_file.
The default implementation does nothing.
@param success the return value of renderer.setFile() which
indicates if the file could be successfully loaded by the
renderer, or not. Note that setFile() is called even if the
renderer returned 'false', so that the implemtation can then
disable menu items, etc. */
virtual void setFile(bool success);
/* Creates new instances of DocumentWidget. If you need special
functionality and reimplement the DocumentWidget class, then you
should also reimplement this method to ensure that your new
DocumentWidgets will be used. 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*);
/** This function creates the page cache. If a multipage implementation needs
additional functionaly from the cache overwrite this function to create a
subclass of DocumentPageCache.
@warning This function is called by the constructor, never call it explicitly.
*/
virtual void initializePageCache();
/* Returns a pointer to the renderer. */
virtual TQGuardedPtr<DocumentRenderer> getRenderer() const { return renderer; }
PageView* scrollView() { return _scrollView; }
MarkList* markList() { return _markList; }
// The next two functions are used for the autozoom feature
// TODO optimize (the calculation of the widest page needs to be done only once
// per document, not everytime calculateFitToWidthZoomValue() is called)
PageNumber widestPage() const;
// TODO Generalize this for more than 2 columns
double zoomForWidthColumns(unsigned int viewportWidth) const;
public slots:
virtual void doSelectAll();
virtual void clearSelection();
virtual void copyText();
/** Exports the document to a plain text file. */
virtual void doExportText();
/* Shows the "text search" dialog, if text search is supported by
the renderer. Otherwise, the method returns immediately. */
virtual void showFindTextDialog();
/* 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. */
virtual void findNextText();
/* 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. */
virtual void findPrevText();
/** 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();
/* Initialize/Update PageWidgets, thumbnail list and bookmark list
This slot is called after a document was loaded, when the
document was modified (e.g. when pages were deleted), or the
rendering mode is changed (e.g. when a different accessibility
viewmode is selected). The following is done
- The page cache is cleared
- all page widgets as well as the thumbnails are updated.
*/
void renderModeChanged();
/* 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);
/* Is called if settings are changed in the configuration dialog.
If this method is reimplemented in a child class, it needs to be
called from there. */
virtual void preferencesChanged();
/* Page Navigation. */
virtual bool gotoPage(const PageNumber& page);
virtual void gotoPage(const Anchor& a);
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);
virtual void slotEnableMoveTool(bool enable);
protected slots:
virtual bool gotoPage(const PageNumber& page, int y, bool isLink = true);
/* Make the selection visible */
void gotoPage(const TextSelection&);
private slots:
void handleLocalLink(const TQString &linkText);
signals:
/** Emitted with argument "true" when the move tool is selected, and
with argument "false" if selection tool is selected. */
void enableMoveTool(bool enable);
/* Emitted when a page has been selected in the MarkList. */
void selected(const 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();
void zoomOut();
void zoomIn();
/* Emitted it the status of the text selection changes. */
void textSelected(bool);
void searchEnabled(bool);
// Interface definition end --------------------------------------------------
public slots:
virtual void generateDocumentWidgets(const PageNumber& startPage = PageNumber::invalidPage);
protected slots:
/* This is the slot where mouseWheel events are processed that come
from the multipage/scrollview. This method calles scroll, a
delta-value of 120 (i.e. one notch on a standard wheel mouse)
scrolls by two 'lines'. */
void wheelEvent(TQWheelEvent *);
protected:
/** Allocates and initializes a KPrinter structure
This method is used in implementations of the print() method. See
the documentation of print() for more information and for example
code. This method allocates and initializes a KPrinter
structure. The list of pages marked in the sidebar is already set in
the "kde-range" option in the KPrinter structure. In this option "1"
means: first page of the document, "2" the second, etc.
@param enablePageSizeFeatures Enables or diables the entries in the
"Page Size & Placement" tab of the print dialog.
@returns a pointer to a KPrinter, or 0 if no KPrinter could be
allocated.
@warning The KPrinter allocated is owned by the caller must be
deleted before the KMultiPage is deleted. Otherwise, a segfault will
occur.
*/
KPrinter *getPrinter(bool enablePageSizeFeatures=true);
/** Pointer to the parent widget
This pointer is automatically set by the constructor.
*/
TQGuardedPtr<TQWidget> parentWdg;
TQPtrVector<DocumentWidget> widgetList;
History document_history;
/* Variable which is used internally by the method
currentPageNumber() to provide 'lazy' page numbers. */
PageNumber lastCurrentPage;
/* The pageCache caches already drawn "documentPages" and invokes
the renderer if the needed page is not available in the cache. */
DocumentPageCache* pageCache;
private slots:
void setCurrentPageNumber(const PageNumber&);
void updateWidgetSize(const PageNumber&);
/* Interrupts a search if one is currently performed, otherwise
hide the search panel */
void stopSearch();
private:
/* For internal use by the reload()-method. See the comments in
kmultipage.cpp, right before the timerEvent function. */
int timer_id;
/* For internal use the reload()-method. This is a dreadful
hack. The problem we adress with this timer event is the
following: the kviewshell has a KDirWatch object which looks at
the DVI file and calls reload() when the object has changed. That
works very nicely in principle, but in practise, when TeX runs
for several seconds over a complicated file, this does not work
at all. First, most of the time, while TeX is still writing, the
file is invalid. Thus, reload() is very often called when the DVI
file is bad. We solve this problem by checking the file first. If
the file is bad, we do not reload. Second, when the file finally
becomes good, it very often happens that KDirWatch does not
notify us anymore. Whether this is a bug or a side effect of a
feature of KDirWatch, I dare not say. We remedy that problem by
using a timer: when reload() was called on a bad file, we
automatically come back (via the timerEvent() function) every
second and check if the file became good. If so, we stop the
timer. It may well happen that KDirWatch calls us several times
while we are waiting for the file to become good, but that does
not do any harm. */
void timerEvent( TQTimerEvent *e );
/* This method opens a file and sets up the GUI when the file is
loaded. It calls setFile() so that implementations of kmultipage
can update their own GUI. DO NOT REIMPLEMENT THIS METHOD. */
bool openFile();
/* Is set by setRenderer. */
TQGuardedPtr<DocumentRenderer> renderer;
PageView *_scrollView;
SearchWidget* searchWidget;
TQToolBox* sideBar;
MarkList* _markList;
TableOfContents* tableOfContents;
TQSplitter* splitterWidget;
/* 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. */
TQTimer changePageDelayTimer;
// This is set to true while a text search is performed.
// If set to false the search is interrupted.
bool searchInProgress;
};
#endif
|