1 // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; c-brace-offset: 0; -*-
5 // Class for rendering TeX DVI files.
6 // Part of KDVI- A previewer for TeX DVI files.
8 // (C) 2001-2005 Stefan Kebekus
9 // Distributed under the GPL
14 #include "dviRenderer.h"
16 #include "dvisourcesplitter.h"
17 #include "hyperlink.h"
18 #include "kvs_debug.h"
19 #include "prebookmark.h"
21 //#include "renderedDviPagePixmap.h"
22 #include "dviPageInfo.h"
29 #include <kmessagebox.h>
30 #include <kmimetype.h>
31 #include <kstandarddirs.h>
34 #include <QApplication>
38 #include <QHBoxLayout>
41 #include <QProgressBar>
44 //#define DEBUG_DVIRENDERER
46 QPainter
*foreGroundPainter
; // QPainter used for text
49 //------ now comes the dviRenderer class implementation ----------
51 dviRenderer::dviRenderer()
55 embedPS_numOfProgressedFiles(0),
60 PostScriptOutPutString(0),
61 PS_interface(new ghostscript_interface
),
63 line_boundary_encountered(false),
64 word_boundary_encountered(false),
67 number_of_elements_in_path(0),
68 currentlyDrawnPage(0),
71 #ifdef DEBUG_DVIRENDERER
72 //kDebug(kvs::dvi) << "dviRenderer( parent=" << par << " )";
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";
88 QMutexLocker
locker(&mutex
);
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
);
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;
123 // Paranoid safety checks
125 kError(kvs::dvi
) << "dviRenderer::drawPage(documentPage *) called with argument == 0" << endl
;
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
;
134 QMutexLocker
locker(&mutex
);
137 if ( dviFile
== 0 ) {
138 kError(kvs::dvi
) << "dviRenderer::drawPage(documentPage *) called, but no dviFile class allocated." << endl
;
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
;
147 if ( dviFile
->dvi_Data() == 0 ) {
148 kError(kvs::dvi
) << "dviRenderer::drawPage(documentPage *) called, but no dviFile is loaded yet." << endl
;
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;
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) {
175 delete foreGroundPainter
;
176 foreGroundPainter
= 0;
180 kDebug(kvs::dvi
) << "painter creation failed.";
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.
196 if (j
== page
->hyperLinkList
.end())
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
)
208 hi
.box
= hi
.box
.unite(hj
.box
);
211 if (j
== page
->hyperLinkList
.end())
219 i
= page
->hyperLinkList
.erase(++i
, j
);
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"));
235 currentlyDrawnPage
= 0;
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
);
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
249 //QTimer::singleShot( 0, this, SLOT(showThatSourceInformationIsPresent()) );
253 currentlyDrawnPage
= 0;
257 void dviRenderer::getText(RenderedDocumentPagePixmap
* page
)
259 bool postscriptBackup
= _postscript
;
260 // Disable postscript-specials temporarely to speed up text extraction.
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);
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);
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>"),
300 label2->setMinimumSize(label2->sizeHint());
301 lay->addWidget(label2);
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 );
314 showMsg = !checkbox->isChecked();
316 KConfigGroup saver(config, "Notification Messages");
317 config->writeEntry( "KDVI-info_on_source_specials", showMsg);
324 void dviRenderer::embedPostScript()
326 #ifdef DEBUG_DVIRENDERER
327 kDebug(kvs::dvi
) << "dviRenderer::embedPostScript()";
333 /* embedPS_progress = new KProgressDialog(parentWidget,
334 i18n("Embedding PostScript Files"), QString(), true); */
335 if (!embedPS_progress
)
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
;
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)];
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);
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();
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)];
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";
404 current_page
= currPageSav
;
409 bool dviRenderer::isValidFile(const QString
& filename
) const
412 if (!f
.open(QIODevice::ReadOnly
))
415 unsigned char test
[4];
416 if ( f
.read( (char *)test
,2)<2 || test
[0] != 247 || test
[1] != 2 )
420 if ( n
< 134 ) // Too short for a dvi file
424 unsigned char trailer
[4] = { 0xdf,0xdf,0xdf,0xdf };
426 if ( f
.read( (char *)test
, 4 )<4 || strncmp( (char *)test
, (char *) trailer
, 4 ) )
428 // We suppose now that the dvi file is complete and OK
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 << " )";
438 //QMutexLocker lock(&mutex);
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()) {
448 info->setDVIData(0);*/
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),
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;
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"));*/
486 dviFile
= dviFile_new
;
487 numPages
= dviFile
->total_pages
;
489 info->setDVIData(dviFile); */
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.
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();
517 prebookmarks
.clear();
519 if (dviFile
->page_offset
.isEmpty() == true)
523 font_pool
.locateFonts();
525 // Update the list of fonts in the info window
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();
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)];
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
;
563 // Generate the list of bookmarks
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
));
571 bookmarks
.append(bmk
);
573 stack
.top()->subordinateBookmarks
.append(bmk
);
576 for(int i
=0; i
<(*it
).noOfChildren
; i
++)
579 prebookmarks
.clear();
582 #ifdef PERFORMANCE_MEASUREMENT
583 //kDebug(kvs::dvi) << "Time required for prescan phase: " << preScanTimer.restart() << "ms";
585 current_page
= currPageSav
;
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();
597 Anchor
dviRenderer::parseReference(const QString
&reference
)
599 QMutexLocker
locker(&mutex
);
601 #ifdef DEBUG_DVIRENDERER
602 kError(kvs::dvi
) << "dviRenderer::parseReference( " << reference
<< " ) called" << endl
;
608 // case 1: The reference is a number, which we'll interpret as a
611 int page
= reference
.toInt ( &ok
);
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"));
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
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
) ) )
672 if (bestMatch
!= sourceHyperLinkAnchors
.end())
673 return Anchor(bestMatch
->page
, bestMatch
->distance_from_top
);
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" ));
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)
699 resolutionInDPI
= resolution_in_DPI
;
701 // Pass the information on to the font pool.
702 font_pool
.setDisplayResolution( resolutionInDPI
);
703 shrinkfactor
= 1200/resolutionInDPI
;
708 void dviRenderer::clearStatusBar()
710 //emit setStatusBarText( QString() );
714 void dviRenderer::handleSRCLink(const QString
&linkText
, const QPoint
& point
, DocumentWidget
*win
)
716 Q_UNUSED( linkText
);
720 KSharedPtr
<DVISourceEditor
> editor(new DVISourceEditor(*this, parentWidget
, linkText
, point
, win
));
721 if (editor
->started())
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
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)));
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)
782 info->outputReceiver(text);
785 void dviRenderer::editor_finished(const DVISourceEditor*)
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
)
810 #include "dviRenderer.moc"