#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "kviewpart.h" #include "optiondialog.h" #include "kdvi_multipage.h" extern "C" { void *init_libkdvi() { KGlobal::locale()->insertCatalogue("kviewshell"); return new KDVIMultiPageFactory; } }; KInstance *KDVIMultiPageFactory::s_instance = 0L; KDVIMultiPageFactory::KDVIMultiPageFactory() { } KDVIMultiPageFactory::~KDVIMultiPageFactory() { if (s_instance) delete s_instance; s_instance = 0; } KParts::Part *KDVIMultiPageFactory::createPartObject( QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name, const char *, const QStringList & ) { KParts::Part *obj = new KDVIMultiPage(parentWidget, widgetName, parent, name); return obj; } KInstance *KDVIMultiPageFactory::instance() { if (!s_instance) s_instance = new KInstance("kdvi"); return s_instance; } KDVIMultiPage::KDVIMultiPage(QWidget *parentWidget, const char *widgetName, QObject *parent, const char *name) : KMultiPage(parentWidget, widgetName, parent, name), window(0), options(0) { timer_id = -1; setInstance(KDVIMultiPageFactory::instance()); printer = 0; document_history.clear(); window = new dviWindow( 1.0, true, scrollView()); preferencesChanged(); connect( window, SIGNAL( setStatusBarText( const QString& ) ), this, SIGNAL( setStatusBarText( const QString& ) ) ); docInfoAction = new KAction(i18n("Document &Info"), 0, this, SLOT(doInfo()), actionCollection(), "info_dvi"); backAction = KStdAction::back(this, SLOT(doGoBack()), actionCollection(), "go_back"); forwardAction = KStdAction::forward(this, SLOT(doGoForward()), actionCollection(), "go_forward"); document_history.setAction(backAction, forwardAction); document_history.clear(); findTextAction = KStdAction::find(window, SLOT(showFindTextDialog()), actionCollection(), "find"); window->findNextAction = KStdAction::findNext(window, SLOT(findNextText()), actionCollection(), "findnext"); window->findNextAction->setEnabled(false); window->findPrevAction = KStdAction::findPrev(window, SLOT(findPrevText()), actionCollection(), "findprev"); window->findPrevAction->setEnabled(false); copyTextAction = KStdAction::copy(window, SLOT(copyText()), actionCollection(), "copy_text"); window->DVIselection.setAction(copyTextAction); selectAllAction = KStdAction::selectAll(this, SLOT(doSelectAll()), actionCollection(), "edit_select_all"); new KAction(i18n("Enable All Warnings and Messages"), 0, this, SLOT(doEnableWarnings()), actionCollection(), "enable_msgs"); exportPSAction = new KAction(i18n("PostScript"), 0, this, SLOT(doExportPS()), actionCollection(), "export_postscript"); exportPDFAction = new KAction(i18n("PDF"), 0, this, SLOT(doExportPDF()), actionCollection(), "export_pdf"); exportTextAction = new KAction(i18n("Text"), 0, this, SLOT(doExportText()), actionCollection(), "export_text"); new KAction(i18n("&DVI Options"), 0, this, SLOT(doSettings()), actionCollection(), "settings_dvi"); new KAction(i18n("&Tip of the Day..."), 0, this, SLOT(showTip()), actionCollection(), "help_tipofday"); new KAction(i18n("About the KDVI plugin..."), 0, this, SLOT(about()), actionCollection(), "about_kdvi"); new KAction(i18n("Help on the KDVI plugin..."), 0, this, SLOT(helpme()), actionCollection(), "help_dvi"); new KAction(i18n("Report Bug in the KDVI plugin..."), 0, this, SLOT(bugform()), actionCollection(), "bug_dvi"); setXMLFile("kdvi_part.rc"); scrollView()->addChild(window); connect(window, SIGNAL(request_goto_page(int, int)), this, SLOT(goto_page(int, int) ) ); connect(window, SIGNAL(contents_changed(void)), this, SLOT(contents_of_dviwin_changed(void)) ); readSettings(); enableActions(false); // Show tip of the day, when the first main window is shown. QTimer::singleShot(0,this,SLOT(showTipOnStart())); } KDVIMultiPage::~KDVIMultiPage() { if (timer_id != -1) killTimer(timer_id); timer_id = -1; writeSettings(); if (printer != 0) delete printer; } bool KDVIMultiPage::openFile() { document_history.clear(); emit setStatusBarText(QString(i18n("Loading file %1")).arg(m_file)); bool r = window->setFile(m_file,url().ref()); if (!r) emit setStatusBarText(QString::null); window->changePageSize(); // This also calles drawPage(); emit numberOfPages(window->totalPages()); enableActions(r); return r; } void KDVIMultiPage::jumpToReference(QString reference) { kdError() << "Reference: " << reference << endl; if (window != 0) { window->reference = reference; window->all_fonts_loaded(); // In spite of its name, this method tries to parse the reference. } } void KDVIMultiPage::contents_of_dviwin_changed(void) { emit previewChanged(true); } bool KDVIMultiPage::closeURL() { document_history.clear(); window->setFile(""); // That means: close the file. Resize the widget to 0x0. enableActions(false); return true; } QStringList KDVIMultiPage::fileFormats() { QStringList r; r << i18n("*.dvi *.DVI|TeX Device Independent files (*.dvi)"); return r; } bool KDVIMultiPage::gotoPage(int page) { document_history.add(page,0); window->gotoPage(page+1); return true; } void KDVIMultiPage::goto_page(int page, int y) { document_history.add(page,y); if (y != 0) window->gotoPage(page+1, y); else window->gotoPage(page+1); scrollView()->ensureVisible(scrollView()->width()/2, y ); emit pageInfo(window->totalPages(), page ); } double KDVIMultiPage::setZoom(double zoom) { if (zoom < KViewPart::minZoom/1000.0) zoom = KViewPart::minZoom/1000.0; if (zoom > KViewPart::maxZoom/1000.0) zoom = KViewPart::maxZoom/1000.0; double z = window->setZoom(zoom); scrollView()->resizeContents(window->width(), window->height()); return z; } double KDVIMultiPage::zoomForHeight(int height) { return (double)(height-1)/(window->xres*(window->paper_height/2.54)); } double KDVIMultiPage::zoomForWidth(int width) { return (double)(width-1)/(window->xres*(window->paper_width/2.54)); } void KDVIMultiPage::setPaperSize(double w, double h) { window->setPaper(w, h); } bool KDVIMultiPage::preview(QPainter *p, int w, int h) { QPixmap *map = window->pix(); if (!map) return false; p->scale((double)w/(double)map->width(), (double)h/(double)map->height()); p->drawPixmap(0, 0, *map); return true; } void KDVIMultiPage::doInfo(void) { window->showInfo(); } void KDVIMultiPage::doSelectAll(void) { window->selectAll(); } void KDVIMultiPage::doExportPS(void) { window->exportPS(); } void KDVIMultiPage::doExportPDF(void) { window->exportPDF(); } void KDVIMultiPage::doExportText(void) { window->exportText(); } void KDVIMultiPage::doSettings() { if (!options) { options = new OptionDialog(window); connect(options, SIGNAL(preferencesChanged()), this, SLOT(preferencesChanged())); } options->show(); } void KDVIMultiPage::about() { KAboutDialog *ab = new KAboutDialog(KAboutDialog::AbtAppStandard, i18n("the KDVI plugin"), KAboutDialog::Close, KAboutDialog::Close); ab->setProduct("kdvi", "1.0", QString::null, QString::null); ab->addTextPage (i18n("About"), i18n("A previewer for Device Independent files (DVI files) produced " "by the TeX typesetting system.
" "Based on kdvi 0.4.3 and on xdvik, version 18f.

" "For latest information, visit " "KDVI's Homepage."), true); ab->addTextPage (i18n("Authors"), i18n("Stefan Kebekus
" "" "http://btm8x5.mat.uni-bayreuth.de/~kebekus
" "kebekus@kde.org
" "Current maintainer of kdvi. Major rewrite of version 0.4.3." "Implementation of hyperlinks.
" "
" "Markku Hinhala
" "Author of kdvi 0.4.3" "
" "Nicolai Langfeldt
" "Maintainer of xdvik" "
" "Paul Vojta
" " Author of xdvi
" "
" "Many others. Really, lots of people who were involved in kdvi, xdvik and " "xdvi. I apologize to those who I did not mention here. Please send me an " "email if you think your name belongs here."), true); ab->setMinimumWidth(500); ab->show(); } void KDVIMultiPage::bugform() { KAboutData *kab = new KAboutData("kdvi", I18N_NOOP("KDVI"), "1.0", 0, 0, 0, 0, 0); KBugReport *kbr = new KBugReport(0, true, kab ); kbr->show(); } void KDVIMultiPage::helpme() { kapp->invokeHelp( "", "kdvi" ); } void KDVIMultiPage::preferencesChanged() { #ifdef DEBUG_MULTIPAGE kdDebug(4300) << "preferencesChanged" << endl; #endif KConfig *config = instance()->config(); QString s; config->reparseConfiguration(); config->setGroup( "kdvi" ); int mfmode = config->readNumEntry( "MetafontMode", DefaultMFMode ); if (( mfmode < 0 ) || (mfmode >= NumberOfMFModes)) config->writeEntry( "MetafontMode", mfmode = DefaultMFMode ); window->setMetafontMode( mfmode ); int makepk = config->readBoolEntry( "MakePK", true ); if ( makepk != window->makePK() ) window->setMakePK( makepk ); int showPS = config->readNumEntry( "ShowPS", 1 ); if (showPS != window->showPS()) window->setShowPS(showPS); int showHyperLinks = config->readNumEntry( "ShowHyperLinks", 1 ); if (showHyperLinks != window->showHyperLinks()) window->setShowHyperLinks(showHyperLinks); window->setEditorCommand( config->readEntry( "EditorCommand", "" )); } bool KDVIMultiPage::print(const QStringList &pages, int current) { // Make sure the KPrinter is available if (printer == 0) { printer = new KPrinter(); if (printer == 0) return false; } // Feed the printer with useful defaults and information. printer->setPageSelection( KPrinter::ApplicationSide ); printer->setCurrentPage( current+1 ); printer->setMinMax( 1, window->totalPages() ); // If pages are marked, give a list of marked pages to the // printer. We try to be smart and optimize the list by using ranges // ("5-11") wherever possible. The user will be tankful for // that. Complicated? Yeah, but that's life. if (pages.isEmpty() == true) printer->setOption( "kde-range", "" ); else { int commaflag = 0; QString range; QStringList::ConstIterator it = pages.begin(); do{ int val = (*it).toUInt()+1; if (commaflag == 1) range += QString(", "); else commaflag = 1; int endval = val; if (it != pages.end()) { QStringList::ConstIterator jt = it; jt++; do{ int val2 = (*jt).toUInt()+1; if (val2 == endval+1) endval++; else break; jt++; } while( jt != pages.end() ); it = jt; } else it++; if (endval == val) range += QString("%1").arg(val); else range += QString("%1-%2").arg(val).arg(endval); } while (it != pages.end() ); printer->setOption( "kde-range", range ); } // Show the printer options requestor if (printer->setup(window) == false) return false; if (printer->pageList().isEmpty() == true) { KMessageBox::error( window, i18n("The list of pages you selected was empty.\n" "Maybe you made an error in selecting the pages, " "e.g. by giving an invalid range like '7-2'.") ); return false; } // Turn the results of the options requestor into a list arguments // which are used by dvips. QString dvips_options = QString::null; // Print in reverse order. if ( printer->pageOrder() == KPrinter::LastPageFirst ) dvips_options += "-r "; // Print only odd pages. if ( printer->pageSet() == KPrinter::OddPages ) dvips_options += "-A "; // Print only even pages. if ( printer->pageSet() == KPrinter::EvenPages ) dvips_options += "-B "; // Orientation if ( printer->orientation() == KPrinter::Landscape ) dvips_options += "-t landscape "; // List of pages to print. QValueList pageList = printer->pageList(); dvips_options += "-pp "; int commaflag = 0; for( QValueList::ConstIterator it = pageList.begin(); it != pageList.end(); ++it ) { if (commaflag == 1) dvips_options += QString(","); else commaflag = 1; dvips_options += QString("%1").arg((*it)-1); } // Now print. For that, export the DVI-File to PostScript. Note that // dvips will run concurrently to keep the GUI responsive, keep log // of dvips and allow abort. Giving a non-zero printer argument // means that the dvi-widget will print the file when dvips // terminates, and then delete the output file. KTempFile tf; window->exportPS(tf.name(), dvips_options, printer); // "True" may be a bit euphemistic. However, since dvips runs // concurrently, there is no way of telling the result of the // printing command at this stage. return true; } // Explanation of the timerEvent. // // 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 becaome 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. // // -- Stefan Kebekus. void KDVIMultiPage::timerEvent( QTimerEvent * ) { #ifdef DEBUG_MULTIPAGE kdDebug(4300) << "Timer Event " << endl; #endif reload(); } void KDVIMultiPage::reload() { #ifdef DEBUG_MULTIPAGE kdDebug(4300) << "Reload file " << m_file << endl; #endif if (window->correctDVI(m_file)) { killTimer(timer_id); timer_id = -1; int currsav = window->curr_page(); bool r = window->setFile(m_file, QString::null, false); enableActions(r); // Go to the old page and tell kviewshell where we are. window->gotoPage(currsav); // We don't use "currsav" here, because that page may no longer // exist. In that case, gotoPage already selected another page. emit pageInfo(window->totalPages(), window->curr_page()-1 ); } else { if (timer_id == -1) timer_id = startTimer(1000); } } void KDVIMultiPage::enableActions(bool b) { docInfoAction->setEnabled(b); selectAllAction->setEnabled(b); findTextAction->setEnabled(b); exportPSAction->setEnabled(b); exportPDFAction->setEnabled(b); exportTextAction->setEnabled(b); } void KDVIMultiPage::doGoBack(void) { historyItem *it = document_history.back(); if (it != 0) goto_page(it->page, it->ypos); else kdDebug(4300) << "Faulty return -- bad history buffer" << endl; return; } void KDVIMultiPage::doGoForward(void) { historyItem *it = document_history.forward(); if (it != 0) goto_page(it->page, it->ypos); else kdDebug(4300) << "Faulty return -- bad history buffer" << endl; return; } void KDVIMultiPage::doEnableWarnings(void) { KMessageBox::information (window, i18n("All messages and warnings will now be shown.")); KMessageBox::enableAllMessages(); kapp->config()->reparseConfiguration(); KTipDialog::setShowOnStart(true); } void KDVIMultiPage::showTip(void) { KTipDialog::showTip(window, "kdvi/tips", true); } void KDVIMultiPage::showTipOnStart(void) { KTipDialog::showTip(window, "kdvi/tips"); } #include "kdvi_multipage.moc"