File indexing completed on 2024-04-21 05:03:25

0001 /**************************************************************************************
0002     begin                : Thu Nov 27 2003
0003     copyright            : (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net)
0004                            (C) 2011-2017 by Michel Ludwig (michel.ludwig@kdemail.net)
0005  **************************************************************************************/
0006 
0007 /***************************************************************************
0008  *                                                                         *
0009  *   This program is free software; you can redistribute it and/or modify  *
0010  *   it under the terms of the GNU General Public License as published by  *
0011  *   the Free Software Foundation; either version 2 of the License, or     *
0012  *   (at your option) any later version.                                   *
0013  *                                                                         *
0014  ***************************************************************************/
0015 
0016 #include "kilestdtools.h"
0017 
0018 #include <QFileInfo>
0019 #include <QRegExp>
0020 
0021 #include <QAction>
0022 #include <KActionCollection>
0023 #include <KConfig>
0024 #include <KLocalizedString>
0025 
0026 #include <KProcess>
0027 
0028 #include "dialogs/listselector.h"
0029 #include "kileconfig.h"
0030 #include "kiletool.h"
0031 #include "kiletoolmanager.h"
0032 #include "kiletool_enums.h"
0033 #include "kileinfo.h"
0034 #include "kiledocmanager.h"
0035 #include "documentinfo.h"
0036 #include "outputinfo.h"
0037 #include "parser/parsermanager.h"
0038 #include "utilities.h"
0039 
0040 #define SHORTCUTS_GROUP_NAME "Shortcuts"
0041 
0042 namespace KileTool
0043 {
0044 Factory::Factory(Manager *mngr, KConfig *config, KActionCollection *actionCollection)
0045     : m_manager(mngr), m_config(config), m_actionCollection(actionCollection)
0046 {
0047     m_standardToolConfigurationFileName = KileUtilities::locate(QStandardPaths::AppDataLocation, "kilestdtools.rc");
0048 }
0049 
0050 Factory::~Factory()
0051 {
0052 }
0053 
0054 Base* Factory::create(const QString& toolName, const QString& config, bool prepare /* = true */)
0055 {
0056     KILE_DEBUG_MAIN << toolName << config << prepare;
0057     KileTool::Base *tool = Q_NULLPTR;
0058     //perhaps we can find the tool in the config file
0059     if (m_config->hasGroup(groupFor(toolName, m_config))) {
0060         KConfigGroup configGroup = m_config->group(groupFor(toolName, m_config));
0061         QString toolClass = configGroup.readEntry("class", QString());
0062 
0063         if(toolClass == "LaTeX") {
0064             tool = new LaTeX(toolName, m_manager, prepare);
0065         }
0066         else if(toolClass == "LaTeXpreview") {
0067             tool = new PreviewLaTeX(toolName, m_manager, prepare);
0068         }
0069         else if(toolClass == "LaTeXLivePreview") {
0070             tool = new LivePreviewLaTeX(toolName, m_manager, prepare);
0071         }
0072         else if(toolClass == "ForwardDVI") {
0073             tool = new ForwardDVI(toolName, m_manager, prepare);
0074         }
0075         else if(toolClass == "ViewHTML") {
0076             tool = new ViewHTML(toolName, m_manager, prepare);
0077         }
0078         else if(toolClass == "ViewBib") {
0079             tool = new ViewBib(toolName, m_manager, prepare);
0080         }
0081         else if(toolClass == "Base") {
0082             tool = new Base(toolName, m_manager, prepare);
0083         }
0084         else if(toolClass == "Compile") {
0085             tool = new Compile(toolName, m_manager, prepare);
0086         }
0087         else if (BibliographyCompile::ToolClass == toolClass) {
0088             tool = new BibliographyCompile(toolName, m_manager, prepare);
0089         }
0090         else if(toolClass == "Convert") {
0091             tool = new Convert(toolName, m_manager, prepare);
0092         }
0093         else if(toolClass == "Archive") {
0094             tool = new Archive(toolName, m_manager, prepare);
0095         }
0096         else if(toolClass == "View") {
0097             tool = new View(toolName, m_manager, prepare);
0098         }
0099         else if(toolClass == "Sequence") {
0100             tool = new Sequence(toolName, m_manager, prepare);
0101         }
0102     }
0103     if(!tool) {
0104         return Q_NULLPTR;
0105     }
0106 
0107     if(!m_manager->configure(tool, config)) {
0108         delete tool;
0109         return Q_NULLPTR;
0110     }
0111     tool->setToolConfig(config);
0112 
0113     // this has to be done after the configuration step only!
0114     if(dynamic_cast<KileTool::Sequence*>(tool)) {
0115         dynamic_cast<KileTool::Sequence*>(tool)->setupSequenceTools();
0116     }
0117 
0118     return tool;
0119 }
0120 
0121 void Factory::resetToolConfigurations()
0122 {
0123     KConfig stdToolConfig(m_standardToolConfigurationFileName, KConfig::NoGlobals);
0124 
0125     m_config->deleteGroup(QLatin1String("Tools"));
0126     m_config->deleteGroup(QLatin1String("ToolsGUI"));
0127 
0128     // we delete all the groups whose names start with "Tool/";
0129     for (const QString& groupName : m_config->groupList()) {
0130         if(groupName.startsWith(QLatin1String("Tool/"))) {
0131             m_config->deleteGroup(groupName);
0132         }
0133     }
0134 
0135     // now we copy all the "Tool/" groups, the "Tools", and "ToolsGUI" groups over
0136     for (const QString& groupName : stdToolConfig.groupList()) {
0137         if(groupName != SHORTCUTS_GROUP_NAME) {
0138             KConfigGroup configGroup = stdToolConfig.group(groupName);
0139             m_config->deleteGroup(groupName);
0140             KConfigGroup newGroup = m_config->group(groupName);
0141             configGroup.copyTo(&newGroup, KConfigGroup::Persistent);
0142         }
0143     }
0144 }
0145 
0146 static void transferKeyStringPairsStartingWith(KConfigGroup& src, KConfigGroup& target, const QString& startsWith)
0147 {
0148     const QStringList keyList = src.keyList();
0149     for (const QString& key : keyList) {
0150         if(key.startsWith(startsWith)) {
0151             QString value = src.readEntry(key, QString());
0152             target.writeEntry(key, value);
0153         }
0154     }
0155 }
0156 
0157 void Factory::installStandardLivePreviewTools()
0158 {
0159     KConfig stdToolConfig(m_standardToolConfigurationFileName, KConfig::NoGlobals);
0160 
0161     const QStringList groupList = stdToolConfig.groupList();
0162     for (const QString& groupName : groupList) {
0163         if(groupName.startsWith(QStringLiteral("Tool/LivePreview"))) {
0164             KConfigGroup configGroup = stdToolConfig.group(groupName);
0165             m_config->deleteGroup(groupName);
0166             KConfigGroup newGroup = m_config->group(groupName);
0167             configGroup.copyTo(&newGroup, KConfigGroup::Persistent);
0168         }
0169     }
0170 
0171     {   // transfer the standard settings inside the "Tools" group
0172         const QString groupName(QStringLiteral("Tools"));
0173         KConfigGroup stdConfigGroup = stdToolConfig.group(groupName);
0174         KConfigGroup newGroup = m_config->group(groupName);
0175         transferKeyStringPairsStartingWith(stdConfigGroup, newGroup, QStringLiteral("LivePreview"));
0176     }
0177 
0178     {   // transfer the standard settings inside the "ToolsGUI" group
0179         const QString groupName(QStringLiteral("ToolsGUI"));
0180         KConfigGroup stdConfigGroup = stdToolConfig.group(groupName);
0181         KConfigGroup newGroup = m_config->group(groupName);
0182         transferKeyStringPairsStartingWith(stdConfigGroup, newGroup, QStringLiteral("LivePreview"));
0183     }
0184 }
0185 
0186 /////////////// LaTeX ////////////////
0187 
0188 LaTeX::LaTeX(const QString& tool, Manager *mngr, bool prepare)
0189     : Compile(tool, mngr, prepare), m_latexOutputHandler(Q_NULLPTR)
0190 {
0191 }
0192 
0193 LaTeX::~LaTeX()
0194 {
0195 }
0196 
0197 void LaTeX::setupAsChildTool(KileTool::Base *child)
0198 {
0199     KileTool::LaTeX *latexChild = dynamic_cast<KileTool::LaTeX*>(child);
0200     if(latexChild) {
0201         latexChild->setLaTeXOutputHandler(latexOutputHandler());
0202     }
0203 }
0204 
0205 LaTeXOutputHandler* LaTeX::latexOutputHandler()
0206 {
0207     return m_latexOutputHandler;
0208 }
0209 
0210 void LaTeX::setLaTeXOutputHandler(LaTeXOutputHandler *h)
0211 {
0212     m_latexOutputHandler = h;
0213 }
0214 
0215 bool LaTeX::determineSource()
0216 {
0217     QString src = source();
0218 
0219     // check whether the source has been set already
0220     if(!src.isEmpty()) {
0221         return true;
0222     }
0223 
0224     //the basedir is determined from the current compile target
0225     //determined by getCompileName()
0226     LaTeXOutputHandler *h = Q_NULLPTR;
0227     src = m_ki->getCompileName(false, &h);
0228 
0229     setSource(src);
0230     setLaTeXOutputHandler(h);
0231 
0232     return true;
0233 }
0234 
0235 int LaTeX::m_reRun = 0;
0236 
0237 // FIXME don't hardcode bbl and ind suffix here.
0238 bool LaTeX::updateBibs(bool checkOnlyBibDependencies)
0239 {
0240     KileDocument::TextInfo *docinfo = manager()->info()->docManager()->textInfoFor(source());
0241     if(docinfo) {
0242         QFileInfo fileinfo(docinfo->url().toLocalFile());
0243         QStringList dependencies;
0244 
0245         if (checkOnlyBibDependencies) {
0246             dependencies = manager()->info()->allBibliographies(docinfo);
0247         }
0248         else {
0249             dependencies = manager()->info()->allDependencies(docinfo);
0250             dependencies.append(fileinfo.fileName());
0251         }
0252         if (!dependencies.empty()) {
0253             return needsUpdate(targetDir() + '/' + S() + ".bbl",
0254                                KileUtilities::lastModifiedFile(dependencies, fileinfo.absolutePath()));
0255         }
0256     }
0257 
0258     return false;
0259 }
0260 
0261 bool LaTeX::updateIndex()
0262 {
0263     KileDocument::TextInfo *docinfo = manager()->info()->docManager()->textInfoFor(source());
0264     if(docinfo) {
0265         QStringList pckgs = manager()->info()->allPackages(docinfo);
0266         if(pckgs.contains("makeidx") || pckgs.contains("imakeidx") || pckgs.contains("splitidx")) {
0267             return needsUpdate(targetDir() + '/' + S() + ".ind", manager()->info()->lastModifiedFile(docinfo));
0268         }
0269     }
0270 
0271     return false;
0272 }
0273 
0274 bool LaTeX::updateAsy()
0275 {
0276     KileDocument::TextInfo *docinfo = manager()->info()->docManager()->textInfoFor(source());
0277     if(docinfo) {
0278         QStringList pckgs = manager()->info()->allPackages(docinfo);
0279         // As asymptote doesn't properly notify the user when it needs to be rerun, we run
0280         // it every time LaTeX is run (but only for m_reRun == 0 if LaTeX has to be rerun).
0281         if(pckgs.contains("asymptote")) {
0282             return true;
0283         }
0284     }
0285     return false;
0286 }
0287 
0288 bool LaTeX::finish(int r)
0289 {
0290     KILE_DEBUG_MAIN << "==bool LaTeX::finish(" << r << ")=====";
0291 
0292     m_toolResult = r;
0293 
0294     if(m_toolResult == AbnormalExit || m_toolResult == Aborted) {
0295         return false;
0296     }
0297 
0298     // in case the compilation failed, we try to parse the log file in order to detect
0299     // errors reported by LaTeX
0300     QString log = targetDir() + '/' + S() + ".log";
0301     manager()->parserManager()->parseOutput(this, log, source());
0302 
0303     return true;
0304 }
0305 
0306 void LaTeX::latexOutputParserResultInstalled()
0307 {
0308     KILE_DEBUG_MAIN;
0309 
0310     if(m_latexOutputHandler) {
0311         m_latexOutputHandler->storeLaTeXOutputParserResult(m_nErrors, m_nWarnings, m_nBadBoxes, m_latexOutputInfoList,
0312                 m_logFile);
0313     }
0314 
0315     checqCriticals();
0316 
0317     if(readEntry("autoRun") == "yes") {
0318         checkAutoRun();
0319     }
0320 
0321     Compile::finish(m_toolResult);
0322 }
0323 
0324 void LaTeX::checqCriticals()
0325 {
0326     // work around the 0 cases as the i18np call can cause some confusion when 0 is passed to it (#275700)
0327     QString es = (m_nErrors == 0 ? i18n("0 errors") : i18np("1 error", "%1 errors", m_nErrors));
0328     QString ws = (m_nWarnings == 0 ? i18n("0 warnings") : i18np("1 warning", "%1 warnings", m_nWarnings));
0329     QString bs = (m_nBadBoxes == 0 ? i18n("0 badboxes") : i18np("1 badbox", "%1 badboxes", m_nBadBoxes));
0330 
0331     sendMessage(Info, i18nc("String displayed in the log panel showing the number of errors/warnings/badboxes",
0332                             "%1, %2, %3", es, ws, bs));
0333 
0334     // jump to first error
0335     if(!isPartOfLivePreview() && m_nErrors > 0 && (readEntry("jumpToFirstError") == "yes")) {
0336         connect(this, SIGNAL(jumpToFirstError()), manager(), SIGNAL(jumpToFirstError()));
0337         emit(jumpToFirstError());
0338     }
0339 }
0340 
0341 void LaTeX::configureLaTeX(KileTool::Base *tool, const QString& source)
0342 {
0343     tool->setSource(source, workingDir());
0344 }
0345 
0346 void LaTeX::configureBibTeX(KileTool::Base *tool, const QString& source)
0347 {
0348     tool->setSource(source, workingDir());
0349 }
0350 
0351 void LaTeX::configureMakeIndex(KileTool::Base *tool, const QString& source)
0352 {
0353     tool->setSource(source, workingDir());
0354 }
0355 
0356 void LaTeX::configureAsymptote(KileTool::Base *tool, const QString& source)
0357 {
0358     tool->setSource(source, workingDir());
0359 }
0360 
0361 // if 'Biblatex' is not used in the document, 'hint' will be empty
0362 ToolConfigPair LaTeX::determineBibliographyBackend(const QString& hint)
0363 {
0364     if(m_latexOutputHandler) {
0365         ToolConfigPair userBibTool = m_latexOutputHandler->bibliographyBackendToolUserOverride();
0366 
0367         if(userBibTool.isValid()) {
0368             // now we still check whether such a tool really exists
0369             if (manager()->containsBibliographyTool(userBibTool)) {
0370                 return userBibTool;
0371             }
0372             else {
0373                 KILE_DEBUG_MAIN << "Cannot find the following bibtool set by the user:" << userBibTool;
0374                 KILE_DEBUG_MAIN << "trying to auto-detect it now!";
0375                 sendMessage(Warning, i18n("Manually selected bibliography tool does not exist: trying to "
0376                                           "auto-detect it now."));
0377             }
0378         }
0379     }
0380 
0381     // we will now try to detect the bib tool by using the given command hint
0382     ToolConfigPair bibTool = manager()->findFirstBibliographyToolForCommand(hint);
0383 
0384     if(m_latexOutputHandler) {
0385         // if we managed to detect a backend, store (or update) it for future runs
0386         if(bibTool.isValid()) {
0387             m_latexOutputHandler->setBibliographyBackendToolAutoDetected(bibTool);
0388         }
0389         else {
0390             // perhaps we have it stored from a previous run?
0391             bibTool = m_latexOutputHandler->bibliographyBackendToolAutoDetected();
0392             // perhaps the bib tools have changed from the previous run?
0393             if (!manager()->containsBibliographyTool(bibTool)) {
0394                 bibTool = ToolConfigPair();
0395             }
0396         }
0397     }
0398 
0399     // this tool must always be available
0400     const ToolConfigPair defaultBibTool = ToolConfigPair(QString("BibTeX"), DEFAULT_TOOL_CONFIGURATION);
0401 
0402     // if no tool has been detected, the default is BibTeX
0403     return bibTool.isValid() ? bibTool : defaultBibTool;
0404 }
0405 
0406 void LaTeX::checkAutoRun()
0407 {
0408     KILE_DEBUG_MAIN << "check for autorun, m_reRun is " << m_reRun;
0409     if(m_reRun >= 2) {
0410         KILE_DEBUG_MAIN << "Already rerun twice, doing nothing.";
0411         m_reRun = 0;
0412         return;
0413     }
0414     if(m_nErrors > 0) {
0415         KILE_DEBUG_MAIN << "Errors found, not running again.";
0416         m_reRun = 0;
0417         return;
0418     }
0419     bool reRunWarningFound = false;
0420     QString bibToolInLaTexOutput;
0421     bool haveUndefinedCitations = false;
0422     // check for "rerun" LaTeX and other tools warnings
0423     if(m_nWarnings > 0) {
0424         int sz = m_latexOutputInfoList.size();
0425         // the messages we are looking for are the last ones (most likely the very last one), so go from end to beginning
0426         for(int i = sz-1; i >= 0; --i) {
0427             if (m_latexOutputInfoList[i].type() == LatexOutputInfo::itmWarning
0428                     && m_latexOutputInfoList[i].message().contains("Rerun", Qt::CaseInsensitive)) {
0429                 // the message could be a message from Biblatex like this:
0430                 // Package biblatex Warning: The following entry could not be found
0431                 // (biblatex)                in the database:
0432                 // (biblatex)                <entry_name>
0433                 // (biblatex)                Please verify the spelling and rerun
0434                 // (biblatex)                LaTeX afterwards.
0435                 //
0436                 // our strategy: if the warning message contains "(biblatex)", Biblatex only
0437                 // suggests to check the source files first, but not to recompile yet
0438                 if (!m_latexOutputInfoList[i].message().contains("(biblatex)", Qt::CaseInsensitive)) {
0439                     reRunWarningFound = true;
0440                     break;
0441                 }
0442             }
0443         }
0444         // Now look for messages from Biblatex like the following:
0445         // Please (re)run Biber on the file:
0446         // or
0447         // Please (re)run Bibtex on the file:
0448         QRegExp biblatexBackendMessage = QRegExp(".*Please \\(re\\)run ([A-Za-z]+) on the file", Qt::CaseInsensitive);
0449         for(int i = sz-1; i >= 0; --i) { // same here, start from the end
0450             if (m_latexOutputInfoList[i].type() == LatexOutputInfo::itmWarning
0451                     && biblatexBackendMessage.indexIn(m_latexOutputInfoList[i].message()) != -1) {
0452                 bibToolInLaTexOutput = biblatexBackendMessage.cap(1);
0453                 KILE_DEBUG_MAIN << "Captured Bib tool: " << bibToolInLaTexOutput;
0454                 break;
0455             }
0456         }
0457         // If we did not get a message from Biblatex about bibtool (re)run, then
0458         // we look for messages like "LaTeX Warning: Citation `A' on page 234 undefined on input line 12345."
0459         // In that case we probably need to (re)run the bibtool.
0460         if (bibToolInLaTexOutput.isEmpty()) {
0461             QRegExp citationUndefinedMessage = QRegExp("Citation `(.+)' on page (\\d+) undefined on input line (\\d+)",
0462                                                Qt::CaseInsensitive);
0463             for(int i = 0; i < sz; ++i) {
0464                 if (m_latexOutputInfoList[i].type() == LatexOutputInfo::itmWarning
0465                         && citationUndefinedMessage.indexIn(m_latexOutputInfoList[i].message()) != -1) {
0466                     haveUndefinedCitations = true;
0467                     KILE_DEBUG_MAIN << "Detected undefined citations";
0468                     break;
0469                 }
0470             }
0471         }
0472     }
0473 
0474     bool asy = (m_reRun == 0) && updateAsy();
0475     // We run bibtool in the following cases:
0476     // 1. Biblatex said that we have to (in this case bibToolInLaTexOutput is not empty), OR
0477     // 2. There are no undefined citations and at least one of the .bib files has a younger modification
0478     //    date than the .bbl file, OR
0479     // 3. We have undefined citations and at least one of the source files (including .bib and .tex) is
0480     //    younger than .bbl.
0481     //    (If the .bbl file is younger than all of them, the next rerun will not change anything)
0482     bool bibs = !bibToolInLaTexOutput.isEmpty() || updateBibs(!haveUndefinedCitations);
0483     bool index = updateIndex();
0484     KILE_DEBUG_MAIN << "asy:" << asy << "bibs:" << bibs << "index:" << index << "reRunWarningFound:" << reRunWarningFound;
0485     // Currently, we don't properly detect yet whether asymptote has to be run.
0486     // So, if asymtote figures are present, we run it each time after the first LaTeX run.
0487     bool reRun = (asy || bibs || index || reRunWarningFound);
0488     KILE_DEBUG_MAIN << "reRun:" << reRun;
0489 
0490     if(reRun) {
0491         KILE_DEBUG_MAIN << "rerunning LaTeX, m_reRun is now " << m_reRun;
0492         Base *tool = manager()->createTool(name(), toolConfig());
0493         if(tool) {
0494             configureLaTeX(tool, source());
0495             // e.g. for LivePreview, it is necessary that the paths are copied to child processes
0496             tool->copyPaths(this);
0497             runChildNext(tool);
0498             m_reRun++;
0499         }
0500     }
0501     else {
0502         m_reRun = 0;
0503     }
0504 
0505     if(bibs) {
0506         KILE_DEBUG_MAIN << "need to run the bibliography tool " << bibToolInLaTexOutput;
0507         ToolConfigPair bibTool = determineBibliographyBackend(bibToolInLaTexOutput);
0508         Base *tool = manager()->createTool(bibTool.first, bibTool.second);
0509         if(tool) {
0510             configureBibTeX(tool, targetDir() + '/' + S() + '.' + tool->from());
0511             // e.g. for LivePreview, it is necessary that the paths are copied to child processes
0512             tool->copyPaths(this);
0513             runChildNext(tool);
0514         }
0515     }
0516 
0517     if(index) {
0518         KILE_DEBUG_MAIN << "need to run MakeIndex";
0519         Base *tool = manager()->createTool("MakeIndex", QString());
0520         if(tool) {
0521             KILE_DEBUG_MAIN << targetDir() << S() << tool->from();
0522             configureMakeIndex(tool, targetDir() + '/' + S() + '.' + tool->from());
0523             // e.g. for LivePreview, it is necessary that the paths are copied to child processes
0524             tool->copyPaths(this);
0525             runChildNext(tool);
0526         }
0527     }
0528 
0529     if(asy) {
0530         KILE_DEBUG_MAIN << "need to run asymptote";
0531         int sz = manager()->info()->allAsyFigures().size();
0532         for(int i = sz -1; i >= 0; --i) {
0533             Base *tool = manager()->createTool("Asymptote", QString());
0534 
0535             if(tool) {
0536                 configureAsymptote(tool, targetDir() + '/' + S() + '-' + QString::number(i + 1) + '.' + tool->from());
0537                 // e.g. for LivePreview, it is necessary that the paths are copied to child processes
0538                 tool->copyPaths(this);
0539                 runChildNext(tool);
0540             }
0541         }
0542     }
0543 }
0544 
0545 
0546 /////////////// PreviewLaTeX (dani) ////////////////
0547 
0548 PreviewLaTeX::PreviewLaTeX(const QString& tool, Manager *mngr, bool prepare) : LaTeX(tool, mngr, prepare)
0549 {
0550 }
0551 
0552 // PreviewLatex makes three steps:
0553 // - filterLogfile()  : parse logfile and read info into InfoLists
0554 // - updateInfoLists(): change entries of temporary file into normal tex file
0555 // - checqCriticals()    : count errors and warnings and emit signals
0556 bool PreviewLaTeX::finish(int r)
0557 {
0558     KILE_DEBUG_MAIN << r;
0559 
0560     m_toolResult = r;
0561 
0562     if(r != Success) {
0563         return Compile::finish(r);
0564     }
0565 
0566     QString log = targetDir() + '/' + S() + ".log";
0567     manager()->parserManager()->parseOutput(this, log, source(), m_filename, m_selrow, m_docrow);
0568 
0569     return true;
0570 }
0571 
0572 void PreviewLaTeX::setPreviewInfo(const QString &filename, int selrow,int docrow)
0573 {
0574     m_filename = filename;
0575     m_selrow = selrow;
0576     m_docrow = docrow;
0577 }
0578 
0579 /////////////// LivePreviewLaTeX ////////////////
0580 
0581 LivePreviewLaTeX::LivePreviewLaTeX(const QString& tool, Manager *mngr, bool prepare)
0582     : LaTeX(tool, mngr, prepare)
0583 {
0584 }
0585 
0586 void LivePreviewLaTeX::configureLaTeX(KileTool::Base *tool, const QString& source)
0587 {
0588     LaTeX::configureLaTeX(tool, source);
0589     tool->setTargetDir(targetDir());
0590 }
0591 
0592 void LivePreviewLaTeX::configureBibTeX(KileTool::Base *tool, const QString& source)
0593 {
0594     tool->setSource(source, targetDir());
0595 }
0596 
0597 void LivePreviewLaTeX::configureMakeIndex(KileTool::Base *tool, const QString& source)
0598 {
0599     tool->setSource(source, targetDir());
0600 }
0601 
0602 void LivePreviewLaTeX::configureAsymptote(KileTool::Base *tool, const QString& source)
0603 {
0604     tool->setSource(source, targetDir());
0605 }
0606 // PreviewLatex makes three steps:
0607 // - filterLogfile()  : parse logfile and read info into InfoLists
0608 // - updateInfoLists(): change entries of temporary file into normal tex file
0609 // - checqCriticals()    : count errors and warnings and emit signals
0610 //  bool LivePreviewLaTeX::finish(int r)
0611 //  {
0612 //      KILE_DEBUG_MAIN << "==bool PreviewLaTeX::finish(" << r << ")=====";
0613 //
0614 //      int nErrors = 0, nWarnings = 0;
0615 //      if(filterLogfile()) {
0616 //          manager()->info()->outputFilter()->updateInfoLists(m_filename,m_selrow,m_docrow);
0617 //          checqCriticals(nErrors,nWarnings);
0618 //      }
0619 //
0620 //      return Compile::finish(r);
0621 //  }
0622 //
0623 //  void LivePreviewLaTeX::setPreviewInfo(const QString &filename, int selrow,int docrow)
0624 //  {
0625 //      m_filename = filename;
0626 //      m_selrow = selrow;
0627 //      m_docrow = docrow;
0628 //  }
0629 
0630 
0631 ForwardDVI::ForwardDVI(const QString& tool, Manager *mngr, bool prepare) : View(tool, mngr, prepare)
0632 {
0633 }
0634 
0635 bool ForwardDVI::checkPrereqs ()
0636 {
0637     KProcess okularVersionTester;
0638     okularVersionTester.setOutputChannelMode(KProcess::MergedChannels);
0639     okularVersionTester.setProgram("okular", QStringList("--version"));
0640     okularVersionTester.start();
0641 
0642     if (okularVersionTester.waitForFinished()) {
0643         QString output = okularVersionTester.readAll();
0644         QRegExp regExp = QRegExp("Okular: (\\d+).(\\d+).(\\d+)");
0645 
0646         if(output.contains(regExp)) {
0647             int majorVersion = regExp.cap(1).toInt();
0648             int minorVersion = regExp.cap(2).toInt();
0649             int veryMinorVersion = regExp.cap(3).toInt();
0650 
0651             //  see https://mail.kde.org/pipermail/okular-devel/2009-May/003741.html
0652             //  the required okular version is > 0.8.5
0653             if(  majorVersion > 0  ||
0654                     ( majorVersion == 0 && minorVersion > 8 ) ||
0655                     ( majorVersion == 0 && minorVersion == 8 && veryMinorVersion > 5 ) ) {
0656                 ; // everything okay
0657             }
0658             else {
0659                 sendMessage(Error,i18n("The version %1.%2.%3 of okular is too old for ForwardDVI. Please update okular to version 0.8.6 or higher",majorVersion,minorVersion,veryMinorVersion));
0660             }
0661         }
0662     }
0663     // don't return false here because we don't know for sure if okular is used
0664     return true;
0665 }
0666 
0667 bool ForwardDVI::determineTarget()
0668 {
0669     if (!View::determineTarget()) {
0670         return false;
0671     }
0672 
0673     int para = manager()->info()->lineNumber();
0674     KTextEditor::Document *doc = manager()->info()->activeTextDocument();
0675 
0676     if (!doc) {
0677         return false;
0678     }
0679 
0680     QString filepath = doc->url().toLocalFile();
0681     QString texfile = QDir(baseDir()).relativeFilePath(filepath);
0682     QString relativeTarget = "file:" + targetDir() + '/' + target() + "#src:" + QString::number(para + 1) + ' ' + texfile; // space added, for files starting with numbers
0683     QString absoluteTarget = "file:" + targetDir() + '/' + target() + "#src:" + QString::number(para + 1) + filepath;
0684 
0685     if(readEntry("type") == "DocumentViewer") {
0686         addDict("%dir_target", targetDir());
0687         addDict("%target", target());
0688         addDict("%sourceFileName", filepath);
0689         addDict("%sourceLine", QString::number(para + 1));
0690     }
0691     else {
0692         addDict("%dir_target", QString());
0693         addDict("%target", relativeTarget);
0694     }
0695 
0696     addDict("%absolute_target", absoluteTarget);
0697     KILE_DEBUG_MAIN << "==KileTool::ForwardDVI::determineTarget()=============\n";
0698     KILE_DEBUG_MAIN << "\tusing  (absolute)" << absoluteTarget;
0699     KILE_DEBUG_MAIN << "\tusing  (relative)" << relativeTarget;
0700 
0701     return true;
0702 }
0703 
0704 ViewBib::ViewBib(const QString& tool, Manager *mngr, bool prepare) : View(tool, mngr, prepare)
0705 {
0706 }
0707 
0708 bool ViewBib::determineSource()
0709 {
0710     KILE_DEBUG_MAIN << "==ViewBib::determineSource()=======";
0711     if (!View::determineSource()) {
0712         return false;
0713     }
0714 
0715     QString path = source(true);
0716     QFileInfo info(path);
0717 
0718     //get the bibliographies for this source
0719     QStringList bibs = manager()->info()->allBibliographies(manager()->info()->docManager()->textInfoFor(path));
0720     KILE_DEBUG_MAIN << "\tfound " << bibs.count() << " bibs";
0721     if(bibs.count() > 0) {
0722         QString bib = bibs.front();
0723         if (bibs.count() > 1) {
0724             //show dialog
0725             bool bib_selected = false;
0726             KileListSelector *dlg = new KileListSelector(bibs, i18n("Select Bibliography"),i18n("Select a bibliography"));
0727             if (dlg->exec() && dlg->hasSelection()) {
0728                 bib = dlg->selectedItems().first();
0729                 bib_selected = true;
0730                 KILE_DEBUG_MAIN << "Bibliography selected : " << bib;
0731             }
0732             delete dlg;
0733 
0734             if(!bib_selected) {
0735                 sendMessage(Warning, i18n("No bibliography selected."));
0736                 return false;
0737             }
0738         }
0739         KILE_DEBUG_MAIN << "filename before: " << info.path();
0740         setSource(manager()->info()->checkOtherPaths(info.path(),bib + ".bib",KileInfo::bibinputs));
0741     }
0742     else if(info.exists()) { //active doc is a bib file
0743         KILE_DEBUG_MAIN << "filename before: " << info.path();
0744         setSource(manager()->info()->checkOtherPaths(info.path(),info.fileName(),KileInfo::bibinputs));
0745     }
0746     else {
0747         sendMessage(Error, i18n("No bibliographies found."));
0748         return false;
0749     }
0750     return true;
0751 }
0752 
0753 ViewHTML::ViewHTML(const QString& tool, Manager *mngr, bool prepare) : View(tool, mngr, prepare)
0754 {
0755 }
0756 
0757 bool ViewHTML::determineTarget()
0758 {
0759     if (target().isNull()) {
0760         //setRelativeBaseDir(S());
0761         QString dir = readEntry("relDir");
0762         QString trg = readEntry("target");
0763 
0764         if(!dir.isEmpty()) {
0765             translate(dir);
0766             setRelativeBaseDir(dir);
0767         }
0768 
0769         if(!trg.isEmpty()) {
0770             translate(trg);
0771             setTarget(trg);
0772         }
0773 
0774         //auto-detect the file to view
0775         if(dir.isEmpty() && trg.isEmpty()) {
0776             QFileInfo file1 = QFileInfo(baseDir() + '/' + S() + QLatin1String("/index.html"));
0777             QFileInfo file2 = QFileInfo(baseDir() + '/' + S() + QLatin1String(".html"));
0778 
0779             bool read1 = file1.isReadable();
0780             bool read2 = file2.isReadable();
0781 
0782             if(!read1 && !read2) {
0783                 sendMessage(Error, i18n("Unable to find %1 or %2; if you are trying to view some other HTML file, go to Settings->Configure Kile->Tools->ViewHTML->Advanced.", file1.absoluteFilePath(), file2.absoluteFilePath()));
0784                 return false;
0785             }
0786 
0787             //both exist, take most recent
0788             if(read1 && read2) {
0789                 read1 = file1.lastModified() > file2.lastModified();
0790                 read2 = !read1;
0791             }
0792 
0793             if(read1) {
0794                 dir = S();
0795                 trg = "index.html";
0796             }
0797             else if(read2) {
0798                 dir = QLatin1String(".");
0799                 trg = S() + QLatin1String(".html");
0800             }
0801 
0802             translate(dir);
0803             setRelativeBaseDir(dir);
0804             translate(trg);
0805             setTarget(trg);
0806 
0807         }
0808     }
0809 
0810     return View::determineTarget();
0811 }
0812 }
0813 
0814 /*
0815  * BibliographyCompile
0816  */
0817 
0818 const QString KileTool::BibliographyCompile::ToolClass = "Bibliography";
0819 
0820 KileTool::BibliographyCompile::BibliographyCompile(const QString& name, KileTool::Manager* manager, bool prepare)
0821     : Compile(name, manager, prepare)
0822 {
0823 
0824 }
0825 
0826 
0827