compile
[kdegraphics.git] / okular / generators / dvi / dviRenderer.cpp
blob9cc3d2215556ae57ebb77f2ca6ef48d94d5dd81d
1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; c-brace-offset: 0; -*-
2 //
3 // Class: dviRenderer
4 //
5 // Class for rendering TeX DVI files.
6 // Part of KDVI- A previewer for TeX DVI files.
7 //
8 // (C) 2001-2005 Stefan Kebekus
9 // Distributed under the GPL
12 #include <config.h>
14 #include "dviRenderer.h"
15 #include "dviFile.h"
16 #include "dvisourcesplitter.h"
17 #include "hyperlink.h"
18 #include "kvs_debug.h"
19 #include "prebookmark.h"
20 #include "psgs.h"
21 //#include "renderedDviPagePixmap.h"
22 #include "dviPageInfo.h"
24 #include <math.h>
25 #include <QTime>
26 #include <kconfig.h>
27 #include <kglobal.h>
28 #include <klocale.h>
29 #include <kmessagebox.h>
30 #include <kmimetype.h>
31 #include <kstandarddirs.h>
32 #include <kvbox.h>
34 #include <QApplication>
35 #include <QCheckBox>
36 #include <QEventLoop>
37 #include <QFileInfo>
38 #include <QHBoxLayout>
39 #include <QLabel>
40 #include <QPainter>
41 #include <QProgressBar>
42 #include <QRegExp>
44 //#define DEBUG_DVIRENDERER
46 QPainter *foreGroundPainter; // QPainter used for text
49 //------ now comes the dviRenderer class implementation ----------
51 dviRenderer::dviRenderer()
52 : dviFile(0),
53 resolutionInDPI(0),
54 embedPS_progress(0),
55 embedPS_numOfProgressedFiles(0),
56 shrinkfactor(3),
57 source_href(0),
58 HTML_href(0),
59 editorCommand(""),
60 PostScriptOutPutString(0),
61 PS_interface(new ghostscript_interface),
62 _postscript(true),
63 line_boundary_encountered(false),
64 word_boundary_encountered(false),
65 current_page(0),
66 penWidth_in_mInch(0),
67 number_of_elements_in_path(0),
68 currentlyDrawnPage(0),
69 m_eventLoop(0)
71 #ifdef DEBUG_DVIRENDERER
72 //kDebug(kvs::dvi) << "dviRenderer( parent=" << par << " )";
73 #endif
75 // connect(&font_pool, SIGNAL( setStatusBarText( const QString& ) ), this, SIGNAL( setStatusBarText( const QString& ) ) );
76 // connect( &clearStatusBarTimer, SIGNAL(timeout()), this, SLOT(clearStatusBar()) );
77 // pass status bar messages through
78 // connect(PS_interface, SIGNAL( setStatusBarText( const QString& ) ), this, SIGNAL( setStatusBarText( const QString& ) ) );
82 dviRenderer::~dviRenderer()
84 #ifdef DEBUG_DVIRENDERER
85 kDebug(kvs::dvi) << "~dviRenderer";
86 #endif
88 QMutexLocker locker(&mutex);
90 delete PS_interface;
91 delete dviFile;
94 #if 0
95 void dviRenderer::setPrefs(bool flag_showPS, const QString &str_editorCommand, bool useFontHints )
97 //QMutexLocker locker(&mutex);
98 _postscript = flag_showPS;
99 editorCommand = str_editorCommand;
100 font_pool.setParameters( useFontHints );
104 void dviRenderer::showInfo()
106 QMutexLocker locker(&mutex);
108 info->setDVIData(dviFile);
109 info->show();
111 #endif
114 //------ this function calls the dvi interpreter ----------
117 void dviRenderer::drawPage(RenderedDocumentPagePixmap* page)
119 #ifdef DEBUG_DVIRENDERER
120 //kDebug(kvs::dvi) << "dviRenderer::drawPage(documentPage *) called, page number " << page->pageNumber;
121 #endif
123 // Paranoid safety checks
124 if (page == 0) {
125 kError(kvs::dvi) << "dviRenderer::drawPage(documentPage *) called with argument == 0" << endl;
126 return;
128 // Paranoid safety checks
129 if (page->pageNumber == 0) {
130 kError(kvs::dvi) << "dviRenderer::drawPage(documentPage *) called for a documentPage with page number 0" << endl;
131 return;
134 QMutexLocker locker(&mutex);
137 if ( dviFile == 0 ) {
138 kError(kvs::dvi) << "dviRenderer::drawPage(documentPage *) called, but no dviFile class allocated." << endl;
139 page->clear();
140 return;
142 if (page->pageNumber > dviFile->total_pages) {
143 kError(kvs::dvi) << "dviRenderer::drawPage(documentPage *) called for a documentPage with page number " << page->pageNumber
144 << " but the current dviFile has only " << dviFile->total_pages << " pages." << endl;
145 return;
147 if ( dviFile->dvi_Data() == 0 ) {
148 kError(kvs::dvi) << "dviRenderer::drawPage(documentPage *) called, but no dviFile is loaded yet." << endl;
149 page->clear();
150 return;
153 double resolution = page->resolution;
155 if (resolution != resolutionInDPI)
156 setResolution(resolution);
158 currentlyDrawnPage = page;
159 shrinkfactor = 1200/resolutionInDPI;
160 current_page = page->pageNumber-1;
163 // Reset colors
164 colorStack.clear();
165 globalColor = Qt::black;
167 int pageWidth = page->width;
168 int pageHeight = page->height;
170 QImage img(pageWidth, pageHeight, QImage::Format_RGB32);
171 foreGroundPainter = new QPainter(&img);
172 if (foreGroundPainter != 0) {
173 errorMsg.clear();
174 draw_page();
175 delete foreGroundPainter;
176 foreGroundPainter = 0;
178 else
180 kDebug(kvs::dvi) << "painter creation failed.";
182 page->img = img;
183 //page->setImage(img);
185 // Postprocess hyperlinks
186 // Without that, based on the way TeX draws certain characters like german "Umlaute",
187 // some hyperlinks would be broken into two overlapping parts, in the middle of a word.
188 QVector<Hyperlink>::iterator i = page->hyperLinkList.begin();
189 QVector<Hyperlink>::iterator j;
190 while (i != page->hyperLinkList.end())
192 // Iterator j always points to the element after i.
193 j = i;
194 j++;
196 if (j == page->hyperLinkList.end())
197 break;
199 Hyperlink& hi = *i;
200 Hyperlink& hj = *j;
202 bool merged = false;
204 // Merge all hyperlinks that point to the same target, and have the same baseline.
205 while (hi.linkText == hj.linkText && hi.baseline == hj.baseline)
207 merged = true;
208 hi.box = hi.box.unite(hj.box);
210 j++;
211 if (j == page->hyperLinkList.end())
212 break;
214 hj = *j;
217 if (merged)
219 i = page->hyperLinkList.erase(++i, j);
221 else
223 i++;
227 #if 0
228 page->isEmpty = false;
229 if (errorMsg.isEmpty() != true) {
230 KMessageBox::detailedError(parentWidget,
231 i18n("<qt><strong>File corruption</strong> Okular could not interpret your DVI file. This is "
232 "most commonly caused by a corrupted file.</qt>"),
233 errorMsg, i18n("DVI File Error"));
234 errorMsg.clear();
235 currentlyDrawnPage = 0;
236 return;
239 // Tell the user (once) if the DVI file contains source specials
240 // ... we don't want our great feature to go unnoticed.
241 RenderedDviPagePixmap* currentDVIPage = dynamic_cast<RenderedDviPagePixmap*>(currentlyDrawnPage);
242 if (currentDVIPage)
244 if ((dviFile->sourceSpecialMarker == true) && (currentDVIPage->sourceHyperLinkList.size() > 0)) {
245 dviFile->sourceSpecialMarker = false;
246 // Show the dialog as soon as event processing is finished, and
247 // the program is idle
248 //FIXME
249 //QTimer::singleShot( 0, this, SLOT(showThatSourceInformationIsPresent()) );
252 #endif
253 currentlyDrawnPage = 0;
257 void dviRenderer::getText(RenderedDocumentPagePixmap* page)
259 bool postscriptBackup = _postscript;
260 // Disable postscript-specials temporarely to speed up text extraction.
261 _postscript = false;
263 drawPage(page);
265 _postscript = postscriptBackup;
269 void dviRenderer::showThatSourceInformationIsPresent()
271 // In principle, we should use a KMessagebox here, but we want to
272 // add a button "Explain in more detail..." which opens the
273 // Helpcenter. Thus, we practically re-implement the KMessagebox
274 // here. Most of the code is stolen from there.
276 // Check if the 'Don't show again' feature was used
277 KConfig *config = KGlobal::config();
278 KConfigGroup saver(config, "Notification Messages");
279 bool showMsg = config->readEntry( "KDVI-info_on_source_specials", true);
281 if (showMsg) {
282 KDialogBase dialog(i18n("KDVI: Information"), KDialogBase::Yes, KDialogBase::Yes, KDialogBase::Yes,
283 parentWidget, "information", true, true, KStandardGuiItem::ok());
285 KVBox *topcontents = new KVBox (&dialog);
286 topcontents->setSpacing(KDialog::spacingHint()*2);
287 topcontents->setMargin(KDialog::marginHint()*2);
289 QWidget *contents = new QWidget(topcontents);
290 QHBoxLayout * lay = new QHBoxLayout(contents);
291 lay->setSpacing(KDialog::spacingHint()*2);
293 lay->addStretch(1);
294 QLabel *label1 = new QLabel( contents);
295 label1->setPixmap(QMessageBox::standardIcon(QMessageBox::Information));
296 lay->addWidget(label1);
297 QLabel *label2 = new QLabel( i18n("<qt>This DVI file contains source file information. You may click into the text with the "
298 "middle mouse button, and an editor will open the TeX-source file immediately.</qt>"),
299 contents);
300 label2->setMinimumSize(label2->sizeHint());
301 lay->addWidget(label2);
302 lay->addStretch(1);
303 QSize extraSize = QSize(50,30);
304 QCheckBox *checkbox = new QCheckBox(i18n("Do not show this message again"), topcontents);
305 extraSize = QSize(50,0);
306 dialog.setHelpLinkText(i18n("Explain in more detail..."));
307 dialog.setHelp("inverse-search", "kdvi");
308 dialog.enableLinkedHelp(true);
309 dialog.setMainWidget(topcontents);
310 dialog.enableButtonSeparator(false);
311 dialog.incInitialSize( extraSize );
312 dialog.exec();
314 showMsg = !checkbox->isChecked();
315 if (!showMsg) {
316 KConfigGroup saver(config, "Notification Messages");
317 config->writeEntry( "KDVI-info_on_source_specials", showMsg);
319 config->sync();
324 void dviRenderer::embedPostScript()
326 #ifdef DEBUG_DVIRENDERER
327 kDebug(kvs::dvi) << "dviRenderer::embedPostScript()";
328 #endif
330 if (!dviFile)
331 return;
333 /* embedPS_progress = new KProgressDialog(parentWidget,
334 i18n("Embedding PostScript Files"), QString(), true); */
335 if (!embedPS_progress)
336 return;
337 embedPS_progress->setAllowCancel(false);
338 embedPS_progress->showCancelButton(false);
339 embedPS_progress->setMinimumDuration(400);
340 embedPS_progress->progressBar()->setMaximum(dviFile->numberOfExternalPSFiles);
341 embedPS_progress->progressBar()->setValue(0);
342 embedPS_numOfProgressedFiles = 0;
344 quint16 currPageSav = current_page;
345 errorMsg.clear();
346 for(current_page=0; current_page < dviFile->total_pages; current_page++) {
347 if (current_page < dviFile->total_pages) {
348 command_pointer = dviFile->dvi_Data() + dviFile->page_offset[int(current_page)];
349 end_pointer = dviFile->dvi_Data() + dviFile->page_offset[int(current_page+1)];
350 } else
351 command_pointer = end_pointer = 0;
353 memset((char *) &currinf.data, 0, sizeof(currinf.data));
354 currinf.fonttable = &(dviFile->tn_table);
355 currinf._virtual = NULL;
356 prescan(&dviRenderer::prescan_embedPS);
359 delete embedPS_progress;
360 embedPS_progress = 0;
362 if (!errorMsg.isEmpty()) {
363 errorMsg = "<qt>" + errorMsg + "</qt>";
364 // KMessageBox::detailedError(parentWidget, "<qt>" + i18n("Not all PostScript files could be embedded into your document.") + "</qt>", errorMsg);
365 errorMsg.clear();
366 } else
367 /* KMessageBox::information(parentWidget, "<qt>" + i18n("All external PostScript files were embedded into your document. You "
368 "will probably want to save the DVI file now.") + "</qt>",
369 QString(), "embeddingDone");*/
371 // Prescan phase starts here
372 #ifdef PERFORMANCE_MEASUREMENT
373 //kDebug(kvs::dvi) << "Time elapsed till prescan phase starts " << performanceTimer.elapsed() << "ms";
374 //QTime preScanTimer;
375 //preScanTimer.start();
376 #endif
377 dviFile->numberOfExternalPSFiles = 0;
378 prebookmarks.clear();
379 for(current_page=0; current_page < dviFile->total_pages; current_page++) {
380 PostScriptOutPutString = new QString();
382 if (current_page < dviFile->total_pages) {
383 command_pointer = dviFile->dvi_Data() + dviFile->page_offset[int(current_page)];
384 end_pointer = dviFile->dvi_Data() + dviFile->page_offset[int(current_page+1)];
385 } else
386 command_pointer = end_pointer = 0;
388 memset((char *) &currinf.data, 0, sizeof(currinf.data));
389 currinf.fonttable = &(dviFile->tn_table);
390 currinf._virtual = NULL;
392 prescan(&dviRenderer::prescan_parseSpecials);
394 if (!PostScriptOutPutString->isEmpty())
395 PS_interface->setPostScript(current_page, *PostScriptOutPutString);
396 delete PostScriptOutPutString;
398 PostScriptOutPutString = NULL;
401 #ifdef PERFORMANCE_MEASUREMENT
402 //kDebug(kvs::dvi) << "Time required for prescan phase: " << preScanTimer.restart() << "ms";
403 #endif
404 current_page = currPageSav;
405 _isModified = true;
409 bool dviRenderer::isValidFile(const QString& filename) const
411 QFile f(filename);
412 if (!f.open(QIODevice::ReadOnly))
413 return false;
415 unsigned char test[4];
416 if ( f.read( (char *)test,2)<2 || test[0] != 247 || test[1] != 2 )
417 return false;
419 int n = f.size();
420 if ( n < 134 ) // Too short for a dvi file
421 return false;
422 f.seek( n-4 );
424 unsigned char trailer[4] = { 0xdf,0xdf,0xdf,0xdf };
426 if ( f.read( (char *)test, 4 )<4 || strncmp( (char *)test, (char *) trailer, 4 ) )
427 return false;
428 // We suppose now that the dvi file is complete and OK
429 return true;
432 bool dviRenderer::setFile(const QString &fname, const KUrl &base)
434 #ifdef DEBUG_DVIRENDERER
435 kDebug(kvs::dvi) << "dviRenderer::setFile( fname='" << fname << "' )"; //, ref='" << ref << "', sourceMarker=" << sourceMarker << " )";
436 #endif
438 //QMutexLocker lock(&mutex);
440 QFileInfo fi(fname);
441 QString filename = fi.absoluteFilePath();
443 // If fname is the empty string, then this means: "close". Delete
444 // the dvifile and the pixmap.
445 if (fname.isEmpty()) {
446 // Delete DVI file
447 /* if(info)
448 info->setDVIData(0);*/
449 delete dviFile;
450 dviFile = 0;
451 return true;
455 // Make sure the file actually exists.
456 if (!fi.exists() || fi.isDir()) {
458 KMessageBox::error( parentWidget,
459 i18n("<qt><strong>File error.</strong> The specified file '%1' does not exist. "
460 "KDVI already tried to add the ending '.dvi'.</qt>", filename),
461 i18n("File Error"));
463 return false;
466 QApplication::setOverrideCursor( Qt::WaitCursor );
467 dvifile *dviFile_new = new dvifile(filename, &font_pool);
469 if ((dviFile == 0) || (dviFile->filename != filename))
470 dviFile_new->sourceSpecialMarker = true;
471 else
472 dviFile_new->sourceSpecialMarker = false;
474 if ((dviFile_new->dvi_Data() == NULL)||(dviFile_new->errorMsg.isEmpty() != true)) {
475 QApplication::restoreOverrideCursor();
476 if (dviFile_new->errorMsg.isEmpty() != true)
477 /* KMessageBox::detailedError(parentWidget,
478 i18n("<qt>File corruption. KDVI could not interprete your DVI file. This is "
479 "most commonly caused by a corrupted file.</qt>"),
480 dviFile_new->errorMsg, i18n("DVI File Error"));*/
481 delete dviFile_new;
482 return false;
485 delete dviFile;
486 dviFile = dviFile_new;
487 numPages = dviFile->total_pages;
488 /* if(info)
489 info->setDVIData(dviFile); */
490 _isModified = false;
491 baseURL = base;
493 font_pool.setExtraSearchPath( fi.absolutePath() );
494 font_pool.setCMperDVIunit( dviFile->getCmPerDVIunit() );
496 // Extract PostScript from the DVI file, and store the PostScript
497 // specials in PostScriptDirectory, and the headers in the
498 // PostScriptHeaderString.
499 PS_interface->clear();
501 // If the DVI file comes from a remote URL (e.g. downloaded from a
502 // web server), we limit the PostScript files that can be accessed
503 // by this file to the download directory, in order to limit the
504 // possibilities of a denial of service attack.
505 QString includePath;
506 if (!baseURL.isLocalFile()) {
507 includePath = filename;
508 includePath.truncate(includePath.lastIndexOf('/'));
510 PS_interface->setIncludePath(includePath);
512 // We will also generate a list of hyperlink-anchors and source-file
513 // anchors in the document. So declare the existing lists empty.
514 //anchorList.clear();
515 sourceHyperLinkAnchors.clear();
516 //bookmarks.clear();
517 prebookmarks.clear();
519 if (dviFile->page_offset.isEmpty() == true)
520 return false;
522 // Locate fonts.
523 font_pool.locateFonts();
525 // Update the list of fonts in the info window
526 //if (info != 0)
527 //info->setFontInfo(&font_pool);
529 // We should pre-scan the document now (to extract embedded,
530 // PostScript, Hyperlinks, ets).
532 // PRESCAN STARTS HERE
533 #ifdef PERFORMANCE_MEASUREMENT
534 //kDebug(kvs::dvi) << "Time elapsed till prescan phase starts " << performanceTimer.elapsed() << "ms";
535 //QTime preScanTimer;
536 //preScanTimer.start();
537 #endif
538 dviFile->numberOfExternalPSFiles = 0;
539 quint16 currPageSav = current_page;
540 prebookmarks.clear();
542 for(current_page=0; current_page < dviFile->total_pages; current_page++) {
543 PostScriptOutPutString = new QString();
545 if (current_page < dviFile->total_pages) {
546 command_pointer = dviFile->dvi_Data() + dviFile->page_offset[int(current_page)];
547 end_pointer = dviFile->dvi_Data() + dviFile->page_offset[int(current_page+1)];
548 } else
549 command_pointer = end_pointer = 0;
551 memset((char *) &currinf.data, 0, sizeof(currinf.data));
552 currinf.fonttable = &(dviFile->tn_table);
553 currinf._virtual = NULL;
554 prescan(&dviRenderer::prescan_parseSpecials);
556 if (!PostScriptOutPutString->isEmpty())
557 PS_interface->setPostScript(current_page, *PostScriptOutPutString);
558 delete PostScriptOutPutString;
560 PostScriptOutPutString = NULL;
562 #if 0
563 // Generate the list of bookmarks
564 bookmarks.clear();
565 Q3PtrStack<Bookmark> stack;
566 stack.setAutoDelete (false);
567 QVector<PreBookmark>::iterator it;
568 for( it = prebookmarks.begin(); it != prebookmarks.end(); ++it ) {
569 Bookmark *bmk = new Bookmark((*it).title, findAnchor((*it).anchorName));
570 if (stack.isEmpty())
571 bookmarks.append(bmk);
572 else {
573 stack.top()->subordinateBookmarks.append(bmk);
574 stack.remove();
576 for(int i=0; i<(*it).noOfChildren; i++)
577 stack.push(bmk);
579 prebookmarks.clear();
580 #endif
582 #ifdef PERFORMANCE_MEASUREMENT
583 //kDebug(kvs::dvi) << "Time required for prescan phase: " << preScanTimer.restart() << "ms";
584 #endif
585 current_page = currPageSav;
586 // PRESCAN ENDS HERE
588 pageSizes.resize(0);
589 if (dviFile->suggestedPageSize != 0) {
590 // Fill the vector pageSizes with total_pages identical entries
591 pageSizes.fill(*(dviFile->suggestedPageSize), dviFile->total_pages);
593 QApplication::restoreOverrideCursor();
594 return true;
597 Anchor dviRenderer::parseReference(const QString &reference)
599 QMutexLocker locker(&mutex);
601 #ifdef DEBUG_DVIRENDERER
602 kError(kvs::dvi) << "dviRenderer::parseReference( " << reference << " ) called" << endl;
603 #endif
605 if (dviFile == 0)
606 return Anchor();
608 // case 1: The reference is a number, which we'll interpret as a
609 // page number.
610 bool ok;
611 int page = reference.toInt ( &ok );
612 if (ok == true) {
613 if (page < 0)
614 page = 0;
615 if (page > dviFile->total_pages)
616 page = dviFile->total_pages;
618 return Anchor(page, Length() );
621 // case 2: The reference is of form "src:1111Filename", where "1111"
622 // points to line number 1111 in the file "Filename". KDVI then
623 // looks for source specials of the form "src:xxxxFilename", and
624 // tries to find the special with the biggest xxxx
625 if (reference.indexOf("src:", 0, Qt::CaseInsensitive) == 0) {
627 // Extract the file name and the numeral part from the reference string
628 DVI_SourceFileSplitter splitter(reference, dviFile->filename);
629 quint32 refLineNumber = splitter.line();
630 QString refFileName = splitter.filePath();
632 if (sourceHyperLinkAnchors.isEmpty()) {
634 KMessageBox::sorry(parentWidget, i18n("<qt>You have asked KDVI to locate the place in the DVI file which corresponds to "
635 "line %1 in the TeX-file <strong>%2</strong>. It seems, however, that the DVI file "
636 "does not contain the necessary source file information. "
637 "We refer to the manual of KDVI for a detailed explanation on how to include this "
638 "information. Press the F1 key to open the manual.</qt>", refLineNumber, refFileName),
639 i18n("Could Not Find Reference"));
641 return Anchor();
644 // Go through the list of source file anchors, and find the anchor
645 // whose line number is the biggest among those that are smaller
646 // than the refLineNumber. That way, the position in the DVI file
647 // which is highlighted is always a little further up than the
648 // position in the editor, e.g. if the DVI file contains
649 // positional information at the beginning of every paragraph,
650 // KDVI jumps to the beginning of the paragraph that the cursor is
651 // in, and never to the next paragraph. If source file anchors for
652 // the refFileName can be found, but none of their line numbers is
653 // smaller than the refLineNumber, the reason is most likely, that
654 // the cursor in the editor stands somewhere in the preamble of
655 // the LaTeX file. In that case, we jump to the beginning of the
656 // document.
657 bool anchorForRefFileFound = false; // Flag that is set if source file anchors for the refFileName could be found at all
659 QVector<DVI_SourceFileAnchor>::iterator bestMatch = sourceHyperLinkAnchors.end();
660 QVector<DVI_SourceFileAnchor>::iterator it;
661 for( it = sourceHyperLinkAnchors.begin(); it != sourceHyperLinkAnchors.end(); ++it )
662 if (refFileName.trimmed() == it->fileName.trimmed()
663 || refFileName.trimmed() == it->fileName.trimmed() + ".tex"
665 anchorForRefFileFound = true;
667 if ( (it->line <= refLineNumber) &&
668 ( (bestMatch == sourceHyperLinkAnchors.end()) || (it->line > bestMatch->line) ) )
669 bestMatch = it;
672 if (bestMatch != sourceHyperLinkAnchors.end())
673 return Anchor(bestMatch->page, bestMatch->distance_from_top);
674 else
675 if (anchorForRefFileFound == false)
678 KMessageBox::sorry(parentWidget, i18n("<qt>KDVI was not able to locate the place in the DVI file which corresponds to "
679 "line %1 in the TeX-file <strong>%2</strong>.</qt>", refLineNumber, refFileName),
680 i18n( "Could Not Find Reference" ));
683 else
684 return Anchor();
685 return Anchor();
687 return Anchor();
690 void dviRenderer::setResolution(double resolution_in_DPI)
692 // Ignore minute changes. The difference to the current value would
693 // hardly be visible anyway. That saves a lot of re-painting,
694 // e.g. when the user resizes the window, and a flickery mouse
695 // changes the window size by 1 pixel all the time.
696 if (fabs(resolutionInDPI-resolution_in_DPI) < 1)
697 return;
699 resolutionInDPI = resolution_in_DPI;
701 // Pass the information on to the font pool.
702 font_pool.setDisplayResolution( resolutionInDPI );
703 shrinkfactor = 1200/resolutionInDPI;
704 return;
708 void dviRenderer::clearStatusBar()
710 //emit setStatusBarText( QString() );
714 void dviRenderer::handleSRCLink(const QString &linkText, const QPoint& point, DocumentWidget *win)
716 Q_UNUSED( linkText );
717 Q_UNUSED( point );
718 Q_UNUSED( win );
719 #if 0
720 KSharedPtr<DVISourceEditor> editor(new DVISourceEditor(*this, parentWidget, linkText, point, win));
721 if (editor->started())
722 editor_ = editor;
723 #endif
727 QString dviRenderer::PDFencodingToQString(const QString& _pdfstring)
729 // This method locates special PDF characters in a string and
730 // replaces them by UTF8. See Section 3.2.3 of the PDF reference
731 // guide for information.
732 QString pdfstring = _pdfstring;
733 pdfstring = pdfstring.replace("\\n", "\n");
734 pdfstring = pdfstring.replace("\\r", "\n");
735 pdfstring = pdfstring.replace("\\t", "\t");
736 pdfstring = pdfstring.replace("\\f", "\f");
737 pdfstring = pdfstring.replace("\\(", "(");
738 pdfstring = pdfstring.replace("\\)", ")");
739 pdfstring = pdfstring.replace("\\\\", "\\");
741 // Now replace octal character codes with the characters they encode
742 int pos;
743 QRegExp rx( "(\\\\)(\\d\\d\\d)" ); // matches "\xyz" where x,y,z are numbers
744 while((pos = rx.indexIn( pdfstring )) != -1) {
745 pdfstring = pdfstring.replace(pos, 4, QChar(rx.cap(2).toInt(0,8)));
747 rx.setPattern( "(\\\\)(\\d\\d)" ); // matches "\xy" where x,y are numbers
748 while((pos = rx.indexIn( pdfstring )) != -1) {
749 pdfstring = pdfstring.replace(pos, 3, QChar(rx.cap(2).toInt(0,8)));
751 rx.setPattern( "(\\\\)(\\d)" ); // matches "\x" where x is a number
752 while((pos = rx.indexIn( pdfstring )) != -1) {
753 pdfstring = pdfstring.replace(pos, 4, QChar(rx.cap(2).toInt(0,8)));
755 return pdfstring;
759 void dviRenderer::exportPDF()
762 KSharedPtr<DVIExport> exporter(new DVIExportToPDF(*this, parentWidget));
763 if (exporter->started())
764 all_exports_[exporter.data()] = exporter;
769 void dviRenderer::exportPS(const QString& fname, const QStringList& options, QPrinter* printer)
771 KSharedPtr<DVIExport> exporter(new DVIExportToPS(*this, parentWidget, fname, options, printer));
772 if (exporter->started())
773 all_exports_[exporter.data()] = exporter;
777 void dviRenderer::update_info_dialog(const QString& text, bool clear)
779 if (clear)
780 info->clear(text);
781 else
782 info->outputReceiver(text);
785 void dviRenderer::editor_finished(const DVISourceEditor*)
787 editor_.attach(0);
791 void dviRenderer::export_finished(const DVIExport* key)
793 typedef QMap<const DVIExport*, KSharedPtr<DVIExport> > ExportMap;
794 ExportMap::iterator it = all_exports_.find(key);
795 if (it != all_exports_.end())
796 all_exports_.remove(key);
799 void dviRenderer::setEventLoop(QEventLoop *el)
801 if (el == NULL)
803 delete m_eventLoop;
804 m_eventLoop = NULL;
806 else
807 m_eventLoop = el;
810 #include "dviRenderer.moc"