File indexing completed on 2024-03-24 16:41:44

0001 /**************************************************************************************************
0002    Copyright (C) 2005-2007 by Holger Danielsson (holger.danielsson@versanet.de)
0003                  2007-2022 by Michel Ludwig (michel.ludwig@kdemail.net)
0004  **************************************************************************************************/
0005 
0006 /***************************************************************************
0007  *                                                                         *
0008  *   This program is free software; you can redistribute it and/or modify  *
0009  *   it under the terms of the GNU General Public License as published by  *
0010  *   the Free Software Foundation; either version 2 of the License, or     *
0011  *   (at your option) any later version.                                   *
0012  *                                                                         *
0013  ***************************************************************************/
0014 
0015 #include "quickpreview.h"
0016 #include "kiletool_enums.h"
0017 #include "kiledocmanager.h"
0018 #include "widgets/logwidget.h"
0019 
0020 #include <QDir>
0021 #include <QMap>
0022 #include <QFile>
0023 #include <QFileInfo>
0024 #include <QTextCodec>
0025 #include <QTextStream>
0026 
0027 #include <KLocalizedString>
0028 
0029 #include <KTextEditor/Document>
0030 #include <KTextEditor/View>
0031 
0032 #include "errorhandler.h"
0033 #include "kileconstants.h"
0034 #include "kiledebug.h"
0035 
0036 
0037 namespace KileTool
0038 {
0039 
0040 QuickPreview::QuickPreview(KileInfo *ki) : m_ki(ki), m_running(0), m_tempDir(Q_NULLPTR)
0041 {
0042     m_taskList << i18n("LaTeX ---> DVI (Okular)")
0043                << i18n("LaTeX ---> DVI (Document Viewer)")
0044                << i18n("LaTeX ---> PS (Okular)")
0045                << i18n("LaTeX ---> PS (Document Viewer)")
0046                << i18n("PDFLaTeX ---> PDF (Okular)")
0047                << i18n("PDFLaTeX ---> PDF (Document Viewer)")
0048                << i18n("XeLaTeX ---> PDF (Okular)")
0049                << i18n("XeLaTeX ---> PDF (Document Viewer)")
0050                << i18n("LuaLaTeX ---> PDF (Okular)")
0051                << i18n("LuaLaTeX ---> PDF (Document Viewer)")
0052                ;
0053 }
0054 
0055 QuickPreview::~QuickPreview()
0056 {
0057     delete m_tempDir;
0058 }
0059 
0060 //////////////////// quick preview ////////////////////
0061 
0062 // compile and view current selection (singlemode and mastermode)
0063 
0064 void QuickPreview::previewSelection(KTextEditor::View *view, bool previewInWidgetConfig)
0065 {
0066     if (view->selection()) {
0067         int startLine = view->selectionRange().start().line();
0068         KTextEditor::Document *doc = view->document();
0069         if ( previewInWidgetConfig && KileConfig::selPreviewInWidget() ) {
0070             m_ki->previewWidget()->showActivePreview(view->selectionText(), m_ki->getName(doc), startLine, KileTool::qpSelection);
0071         }
0072         else {
0073             run(view->selectionText(), m_ki->getName(doc), startLine);
0074             view->removeSelection();
0075         }
0076     }
0077     else {
0078         showError( i18n("There is no selection to compile.") );
0079     }
0080 }
0081 
0082 // compile and view current environment (singlemode and mastermode)
0083 
0084 void QuickPreview::previewEnvironment(KTextEditor::Document *doc)
0085 {
0086     int row, col;
0087     QString envname;
0088     QString text = m_ki->editorExtension()->getEnvironmentText(row, col, envname);
0089     if (!text.isEmpty()) {
0090         if(m_ki->latexCommands()->isMathModeEnv(envname)) {
0091             text = '$' + text + '$';
0092         }
0093         else if (m_ki->latexCommands()->isDisplaymathModeEnv(envname)) {
0094             text = "\\[" + text + "\\]";
0095         }
0096 
0097         if(KileConfig::envPreviewInWidget()) {
0098             m_ki->previewWidget()->showActivePreview(text, m_ki->getName(doc), row, KileTool::qpEnvironment);
0099         }
0100         else {
0101             run(text, m_ki->getName(doc), row);
0102         }
0103     }
0104     else {
0105         showError(i18n("There is no surrounding environment."));
0106     }
0107 }
0108 
0109 // compile and view current subdocument (only mastermode)
0110 
0111 void QuickPreview::previewSubdocument(KTextEditor::Document *doc)
0112 {
0113     // this mode is only useful with a master document
0114     if(!m_ki->docManager()->activeProject() && m_ki->getSinglemode()) {
0115         showError(i18n("This job is only useful with a master document."));
0116         return;
0117     }
0118 
0119     // the current document should not be the master document
0120     QString filename = doc->url().toLocalFile();
0121     if(filename == m_ki->getCompileName()) {
0122         showError( i18n("This is not a subdocument, but the master document."));
0123         return;
0124     }
0125 
0126     run(doc->text(), m_ki->getName(doc), 0);
0127 }
0128 
0129 // compile and view current mathgroup (singlemode and mastermode)
0130 
0131 void QuickPreview::previewMathgroup(KTextEditor::Document *doc)
0132 {
0133     uint row,col;
0134     QString text = m_ki->editorExtension()->getMathgroupText(row, col);
0135     if (!text.isEmpty()) {
0136         if(KileConfig::mathgroupPreviewInWidget()) {
0137             m_ki->previewWidget()->showActivePreview(text, m_ki->getName(doc), row, KileTool::qpMathgroup);
0138         }
0139         else {
0140             run(text, m_ki->getName(doc), row);
0141         }
0142     }
0143     else {
0144         showError(i18n("There is no surrounding mathgroup."));
0145     }
0146 
0147 }
0148 
0149 //////////////////// run quick preview ////////////////////
0150 
0151 void QuickPreview::getTaskList(QStringList &tasklist)
0152 {
0153     tasklist.clear();
0154     tasklist << "Tool/ViewDVI/Okular="          + m_taskList[0]
0155              << "Tool/ViewDVI/Document Viewer=" + m_taskList[1]
0156              << "Tool/ViewPS/Okular="           + m_taskList[2]
0157              << "Tool/ViewPS/Document Viewer="  + m_taskList[3]
0158              << "Tool/ViewPDF/Okular="          + m_taskList[4]
0159              << "Tool/ViewPDF/Document Viewer=" + m_taskList[5]
0160              << "Tool/ViewPDF/Okular="          + m_taskList[6]
0161              << "Tool/ViewPDF/Document Viewer=" + m_taskList[7]
0162              << "Tool/ViewPDF/Okular="          + m_taskList[8]
0163              << "Tool/ViewPDF/Document Viewer=" + m_taskList[9]
0164              ;
0165 }
0166 
0167 bool QuickPreview::isRunning()
0168 {
0169     return (m_running > 0);
0170 }
0171 
0172 bool QuickPreview::run(const QString &text,const QString &textfilename,int startrow)
0173 {
0174     // define possible tools
0175     QMap <QString,QString> map;
0176     map[m_taskList[0]]  = "PreviewLaTeX,,,ViewDVI,Okular,dvi";
0177     map[m_taskList[1]]  = "PreviewLaTeX,,,ViewDVI,Document Viewer,dvi";
0178     map[m_taskList[2]]  = "PreviewLaTeX,DVItoPS,Default,ViewPS,Okular,ps";
0179     map[m_taskList[3]]  = "PreviewLaTeX,DVItoPS,Default,ViewPS,Document Viewer,ps";
0180     map[m_taskList[4]]  = "PreviewPDFLaTeX,,,ViewPDF,Okular,pdf";
0181     map[m_taskList[5]]  = "PreviewPDFLaTeX,,,ViewPDF,Document Viewer,pdf";
0182     map[m_taskList[6]] = "PreviewXeLaTeX,,,ViewPDF,Okular,pdf";
0183     map[m_taskList[7]] = "PreviewXeLaTeX,,,ViewPDF,Document Viewer,pdf";
0184     map[m_taskList[8]] = "PreviewLuaLaTeX,,,ViewPDF,Okular,pdf";
0185     map[m_taskList[9]] = "PreviewLuaLaTeX,,,ViewPDF,Document Viewer,pdf";
0186 
0187     QString previewtask = KileConfig::previewTask();
0188     if(!map.contains(previewtask)) {
0189         showError(i18n("Could not run QuickPreview:\nunknown task '%1'",previewtask));
0190         return false;
0191     }
0192 
0193     return run (text, textfilename, startrow, map[previewtask]);
0194 }
0195 
0196 bool QuickPreview::run(const QString &text,const QString &textfilename,int startrow,const QString &spreviewlist)
0197 {
0198     KILE_DEBUG_MAIN << "==QuickPreview::run()=========================="  << Qt::endl;
0199     m_ki->errorHandler()->clearMessages();
0200     if(m_running > 0) {
0201         showError( i18n("There is already a preview running that has to be finished to run this one.") );
0202         return false;
0203     }
0204 
0205     // check if there is something to compile
0206     if(text.isEmpty()) {
0207         showError(i18n("There is nothing to compile and preview."));
0208         return false;
0209     }
0210 
0211     delete m_tempDir;
0212     m_tempDir = new QTemporaryDir(QDir::tempPath() + QLatin1Char('/') + "kile-preview");
0213     m_tempDir->setAutoRemove(true);
0214     m_tempFile = QFileInfo(m_tempDir->path(), "preview.tex").absoluteFilePath();
0215     KILE_DEBUG_MAIN << "\tdefine tempfile: " << m_tempFile << Qt::endl;
0216 
0217     // create the temporary file with preamble and text
0218     int preamblelines = createTempfile(text);
0219     if(preamblelines == 0) {
0220         return false;
0221     }
0222 
0223     QStringList previewlist = spreviewlist.split(',', Qt::KeepEmptyParts);
0224 
0225     // create preview tools
0226     KILE_DEBUG_MAIN << "\tcreate latex tool for QuickPreview: "  << previewlist[pvLatex] << Qt::endl;
0227     KileTool::PreviewLaTeX *latex = dynamic_cast<KileTool::PreviewLaTeX*>(m_ki->toolManager()->createTool(previewlist[pvLatex], QString(), false));
0228     if(!latex) {
0229         showError(i18n("Could not run '%1' for QuickPreview.", QString("LaTeX")));
0230         return false;
0231     }
0232 
0233     KileTool::Base *dvips = Q_NULLPTR;
0234     if(!previewlist[1].isEmpty()) {
0235         QString dvipstool = previewlist[pvDvips] + " (" + previewlist[pvDvipsCfg] + ')';
0236         KILE_DEBUG_MAIN << "\tcreate dvips tool for QuickPreview: "  << previewlist[pvDvips] << Qt::endl;
0237         dvips = m_ki->toolManager()->createTool(previewlist[pvDvips], previewlist[pvDvipsCfg]);
0238         if(!dvips) {
0239             showError(i18n("Could not run '%1' for QuickPreview.",dvipstool));
0240             return false;
0241         }
0242     }
0243 
0244     KileTool::Base *viewer = Q_NULLPTR;
0245     if(!previewlist[pvViewer].isEmpty()) {
0246         QString viewertool = previewlist[pvViewer] + " (" + previewlist[pvViewerCfg] + ')';
0247         KILE_DEBUG_MAIN << "\tcreate viewer for QuickPreview: "  << viewertool << Qt::endl;
0248         viewer = m_ki->toolManager()->createTool(previewlist[pvViewer], previewlist[pvViewerCfg], false);
0249         if(!viewer) {
0250             showError(i18n("Could not run '%1' for QuickPreview.",viewertool));
0251             return false;
0252         }
0253     }
0254 
0255     // set value of texinput path (only for QuickPreview tools)
0256     QString texinputpath = KileConfig::teXPaths();
0257     QString inputdir = QFileInfo(m_ki->getCompileName()).absolutePath();
0258     if(!texinputpath.isEmpty()) {
0259         inputdir += LIST_SEPARATOR + texinputpath;
0260     }
0261     KileConfig::setPreviewTeXPaths(inputdir);
0262     KILE_DEBUG_MAIN << "\tQuickPreview: inputdir is '" << inputdir << "'" << Qt::endl;
0263 
0264     // prepare tools: previewlatex
0265     QString filepath = m_tempFile.left(m_tempFile.length() - 3);
0266     latex->setPreviewInfo(textfilename, startrow, preamblelines + 1);
0267     latex->setSource(m_tempFile);
0268     latex->prepareToRun();
0269     latex->setQuickie();
0270     connect(latex, SIGNAL(destroyed()), this, SLOT(toolDestroyed()));
0271     m_ki->toolManager()->run(latex);
0272 
0273     m_running++;
0274 
0275     // dvips
0276     if(dvips) {
0277         dvips->setSource( filepath + "dvi" );
0278         dvips->setQuickie();
0279         connect(dvips, SIGNAL(destroyed()), this, SLOT(toolDestroyed()));
0280         m_ki->toolManager()->run(dvips);
0281 
0282         m_running++;
0283     }
0284 
0285     // viewer
0286     if(viewer) {
0287         connect(viewer, SIGNAL(destroyed()), this, SLOT(toolDestroyed()));
0288         viewer->setSource( filepath + previewlist[pvExtension] );
0289         viewer->setQuickie();
0290         m_ki->toolManager()->run(viewer);
0291     }
0292 
0293     return true;
0294 }
0295 
0296 void QuickPreview::toolDestroyed()
0297 {
0298     KILE_DEBUG_MAIN << "\tQuickPreview: tool destroyed" << Qt::endl;
0299     if(m_running > 0) {
0300         --m_running;
0301     }
0302 }
0303 
0304 QString QuickPreview::getPreviewFile(const QString &extension)
0305 {
0306     if (m_tempFile.length () < 3) {
0307         return QString();
0308     }
0309 
0310     QString filepath = m_tempFile.left(m_tempFile.length () - 3);
0311     return filepath + extension;
0312 }
0313 
0314 //////////////////// tempfile ////////////////////
0315 
0316 int QuickPreview::createTempfile(const QString &text)
0317 {
0318     // determine main document to read the preamble
0319     QString filename = m_ki->getCompileName();
0320     if(filename.isEmpty()) {
0321         showError(i18n("Could not determine the main document."));
0322         return 0;
0323     }
0324 
0325     // open to read
0326     QFile fin(filename);
0327     if(!fin.exists() || !fin.open(QIODevice::ReadOnly)) {
0328         showError(i18n("Could not read the preamble."));
0329         return 0;
0330     }
0331     KILE_DEBUG_MAIN << "\tcreate a temporary file: "  << m_tempFile << Qt::endl;
0332 
0333     // use a textstream
0334     QTextStream preamble(&fin);
0335 
0336     // create the temporary file
0337     QFile tempfile(m_tempFile);
0338     if(!tempfile.open(QIODevice::WriteOnly)) {
0339         showError(i18n("Could not create a temporary file."));
0340         return 0;
0341     }
0342     QTextStream stream(&tempfile);
0343 
0344     // set the encoding according to the original file (tbraun)
0345     if(m_ki->activeTextDocument()) {
0346         QTextCodec *codec = QTextCodec::codecForName(m_ki->activeTextDocument()->encoding().toLatin1());
0347         if(codec) {
0348             stream.setCodec(codec);
0349         }
0350     }
0351     // write the whole preamble into this temporary file
0352     int preamblelines = 0;
0353     bool begindocumentFound = false;
0354     while(!preamble.atEnd()) {
0355         QString textline = preamble.readLine();
0356         if (textline.indexOf("\\begin{document}") >= 0) {
0357             begindocumentFound = true;
0358             break;
0359         }
0360         stream << textline << "\n";
0361         preamblelines++;
0362     }
0363 
0364     // look if we found '\begin{document}' to finish the preamble
0365     if (!begindocumentFound) {
0366         tempfile.close();
0367         showError(i18n("Could not find a '\\begin{document}' command."));
0368         return 0;
0369     }
0370 
0371     // add the text to compile
0372     stream << "\\pagestyle{empty}\n";
0373     stream << "\\begin{document}\n";
0374     stream << text;
0375     stream << "\n\\end{document}\n";
0376     tempfile.close();
0377 
0378     return preamblelines;
0379 }
0380 
0381 //////////////////// error messages ////////////////////
0382 
0383 void QuickPreview::showError(const QString &text)
0384 {
0385     m_ki->errorHandler()->printMessage(KileTool::Error, text, i18n("QuickPreview"));
0386 }
0387 
0388 }
0389