File indexing completed on 2024-04-14 15:17:39

0001 /***************************************************************************
0002   Copyright (C) 2003 by Jeroen Wijnhout (jeroen.wijnhout@kdemail.net)
0003                 2010-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 "kiletool.h"
0016 
0017 #include <QDir>
0018 #include <QFileInfo>
0019 #include <QMetaObject>
0020 #include <QRegExp>
0021 #include <QTimer>
0022 
0023 #include <KConfig>
0024 #include <KLocalizedString>
0025 #include <KShell>
0026 #include <QUrl>
0027 
0028 #include "kileconfig.h"
0029 #include "kiletool_enums.h"
0030 #include "kilestdtools.h" //for the factory
0031 #include "kiletoolmanager.h"
0032 #include "kiledocmanager.h"
0033 #include "kileinfo.h"
0034 #include "documentinfo.h"
0035 #include "kileproject.h"
0036 
0037 namespace KileTool
0038 {
0039 Base::Base(const QString &name, Manager *manager, bool prepare /* = true */) :
0040     QObject(manager), // ensure that they are deleted whenever the tool manager gets deleted
0041     m_launcher(Q_NULLPTR),
0042     m_quickie(false),
0043     m_isPartOfLivePreview(false),
0044     m_manager(manager),
0045     m_name(name),
0046     m_bPrepareToRun(prepare),
0047     m_texInputs(KileConfig::teXPaths()),
0048     m_bibInputs(KileConfig::bibInputPaths()),
0049     m_bstInputs(KileConfig::bstInputPaths()),
0050     m_childToolSpawned(false),
0051     m_toolResult(-1)
0052 {
0053     // WARNING: 'NeedSaveAll' is currently needed to indicate to the tool manager that parsing has to be finished
0054     //          before it launches this tool! This is important to ensure that the right master document is used
0055     //          in the case of projects, for example.
0056     m_flags = NeedTargetDirExec | NeedTargetDirWrite | NeedActiveDoc | NeedMasterDoc | NoUntitledDoc | NeedSourceExists | NeedSourceRead | NeedSaveAll;
0057 
0058     setMsg(NeedTargetDirExec, ki18n("Could not change to the folder %1."));
0059     setMsg(NeedTargetDirWrite, ki18n("The folder %1 is not writable, therefore %2 will not be able to save its results."));
0060     setMsg(NeedTargetExists,  ki18n("The file %1/%2 does not exist. If this is unexpected, check the file permissions."));
0061     setMsg(NeedTargetRead, ki18n("The file %1/%2 is not readable. If this is unexpected, check the file permissions."));
0062     setMsg(NeedActiveDoc, ki18n("Could not determine on which file to run %1, because there is no active document."));
0063     setMsg(NeedMasterDoc, ki18n("Could not determine the master file for this document."));
0064     setMsg(NoUntitledDoc, ki18n("Please save the untitled document first."));
0065     setMsg(NeedSourceExists, ki18n("The file %1 does not exist."));
0066     setMsg(NeedSourceRead, ki18n("The file %1 is not readable."));
0067 
0068     m_bPrepared = false;
0069 }
0070 
0071 Base::~Base()
0072 {
0073     KILE_DEBUG_MAIN << "DELETING TOOL: " << name() << this;
0074     emit(aboutToBeDestroyed(this));
0075     delete m_launcher;
0076 }
0077 
0078 QString Base::source(bool absolute /* = true */) const
0079 {
0080     if (m_source.isEmpty()) {
0081         return QString();
0082     }
0083 
0084     QString src = m_source;
0085     if (absolute) {
0086         src = m_basedir + '/' + src;
0087     }
0088 
0089     return src;
0090 }
0091 
0092 void Base::setMsg(long n, const KLocalizedString& msg)
0093 {
0094     m_messages[n] = msg;
0095 }
0096 
0097 void Base::translate(QString &str, bool quoteForShell)
0098 {
0099     QHashIterator<QString,QString> it(paramDict());
0100     while(it.hasNext()) {
0101         it.next();
0102         QString value;
0103         // the file names in %AFL are quoted already
0104         if(quoteForShell && it.key() != "%AFL") {
0105             value = KShell::quoteArg(it.value());
0106         }
0107         else {
0108             value = it.value();
0109         }
0110         str.replace(it.key(), value);
0111     }
0112 }
0113 
0114 void Base::removeFlag(uint flag)
0115 {
0116     m_flags &= ~flag;
0117 }
0118 
0119 
0120 bool Base::requestSaveAll()
0121 {
0122     return (flags() & NeedSaveAll);
0123 }
0124 
0125 void Base::setEntry(const QString& key, const QString& value)
0126 {
0127     m_entryMap[key] = value;
0128 }
0129 
0130 void Base::prepareToRun()
0131 {
0132     KILE_DEBUG_MAIN << "==Base::prepareToRun()=======";
0133 
0134     //install a launcher
0135     if (!installLauncher())
0136     {
0137         m_nPreparationResult = NoLauncherInstalled;
0138         m_bPrepared = false;
0139         return;
0140     }
0141 
0142     if (!determineSource())
0143     {
0144         m_nPreparationResult = NoValidSource;
0145         m_bPrepared = false;
0146         return;
0147     }
0148 
0149     if (!determineTarget())
0150     {
0151         m_nPreparationResult = NoValidTarget;
0152         m_bPrepared = false;
0153         return;
0154     }
0155 
0156     if ( m_launcher == 0 )
0157     {
0158         m_nPreparationResult = NoLauncherInstalled;
0159         m_bPrepared = false;
0160         return;
0161     }
0162 
0163     if(!workingDir().isEmpty()) {
0164         m_launcher->setWorkingDirectory(workingDir());
0165     }
0166     else {
0167         m_launcher->setWorkingDirectory(baseDir());
0168     }
0169 
0170     //fill in the dictionary
0171     addDict("%options", m_options);
0172 
0173     m_resolution = KileConfig::dvipngResolution() ;
0174     addDict("%res",m_resolution);
0175 
0176     m_bPrepared = true;
0177     m_nPreparationResult = Running;
0178 }
0179 
0180 int Base::run()
0181 {
0182     KILE_DEBUG_MAIN << "==KileTool::Base::run()=================";
0183 
0184     if(m_nPreparationResult != 0) {
0185         emit(failedToRun(this, m_nPreparationResult));
0186         return m_nPreparationResult;
0187     }
0188 
0189     if(!checkSource()) {
0190         emit(failedToRun(this, NoValidSource));
0191         return NoValidSource;
0192     }
0193 
0194     if(!checkTarget()) {
0195         emit(failedToRun(this, TargetHasWrongPermissions));
0196         return TargetHasWrongPermissions;
0197     }
0198 
0199     if (!checkPrereqs()) {
0200         emit(failedToRun(this, NoValidPrereqs));
0201         return NoValidPrereqs;
0202     }
0203 
0204     emit(start(this));
0205 
0206     if (!m_launcher || !m_launcher->launch()) {
0207         KILE_DEBUG_MAIN << "\tlaunching failed";
0208         if(!m_launcher) {
0209             emit(failedToRun(this, CouldNotLaunch));
0210             return CouldNotLaunch;
0211         }
0212         if(!m_launcher->selfCheck()) {
0213             emit(failedToRun(this, SelfCheckFailed));
0214             return SelfCheckFailed;
0215         }
0216         else {
0217             emit(failedToRun(this, CouldNotLaunch));
0218             return CouldNotLaunch;
0219         }
0220     }
0221 
0222     KILE_DEBUG_MAIN << "\trunning...";
0223 
0224     return Running;
0225 
0226 }
0227 
0228 bool Base::determineSource()
0229 {
0230     QString src = source();
0231 
0232     // check whether the source has been set already
0233     if(!src.isEmpty()) {
0234         return true;
0235     }
0236 
0237     //the basedir is determined from the current compile target
0238     //determined by getCompileName()
0239     if(src.isEmpty()) {
0240         src = m_ki->getCompileName();
0241     }
0242     setSource(src);
0243 
0244     return true;
0245 }
0246 
0247 bool Base::checkSource()
0248 {
0249     //FIXME deal with tools that do not need a source or target (yes they exist)
0250     //Is there an active document? Only check if the source file is not explicitly set.
0251     if((m_source.isEmpty()) && (m_manager->info()->activeTextDocument() == Q_NULLPTR)) {
0252         sendMessage(Error, msg(NeedActiveDoc).subs(name()).toString());
0253         return false;
0254     }
0255 
0256     if(m_source.isEmpty() && m_manager->info()->activeTextDocument() != Q_NULLPTR) {
0257         if(m_manager->info()->activeTextDocument()->url().isEmpty()
0258                 && (flags() & NoUntitledDoc)) {
0259             sendMessage(Error, msg(NoUntitledDoc).toString());
0260             return false;
0261         }
0262         else {
0263             //couldn't find a source file, huh?
0264             //we know there is an active document, the only reason is could have failed is because
0265             //we couldn't find a LaTeX root document
0266             sendMessage(Error, msg(NeedMasterDoc).toString());
0267             return false;
0268         }
0269     }
0270 
0271     QFileInfo fi(source());
0272     if((flags() & NeedSourceExists) && !fi.exists()) {
0273         sendMessage(Error, msg(NeedSourceExists).subs(fi.absoluteFilePath()).toString());
0274         return false;
0275     }
0276 
0277     if((flags() & NeedSourceRead) && !fi.isReadable()) {
0278         sendMessage(Error, msg(NeedSourceRead).subs(fi.absoluteFilePath()).toString());
0279         return false;
0280     }
0281 
0282     return true;
0283 }
0284 
0285 void Base::runChildNext(Base *tool, bool block /*= false*/)
0286 {
0287     m_childToolSpawned = true;
0288     if(isPartOfLivePreview()) {
0289         tool->setPartOfLivePreview();
0290     }
0291     manager()->runChildNext(this, tool, block);
0292 }
0293 
0294 void Base::setSource(const QString &source, const QString& workingDir)
0295 {
0296     QFileInfo info(source);
0297 
0298     if(!from().isEmpty()) {
0299         QString src = source;
0300         if(info.suffix().length() > 0) {
0301             src.replace(QRegExp(info.suffix() + '$'), from());
0302         }
0303         info.setFile(src);
0304     }
0305 
0306     if(!workingDir.isEmpty()) {
0307         setWorkingDir(workingDir);
0308     }
0309 
0310     m_basedir = info.absolutePath();
0311     m_source = info.fileName();
0312     m_S = info.completeBaseName();
0313 
0314     addDict("%dir_base", m_basedir);
0315     addDict("%source", m_source);
0316     addDict("%S",m_S);
0317 
0318     KILE_DEBUG_MAIN << "===KileTool::Base::setSource()==============";
0319     KILE_DEBUG_MAIN << "using " << source;
0320     KILE_DEBUG_MAIN << "source="<<m_source;
0321     KILE_DEBUG_MAIN << "S=" << m_S;
0322     KILE_DEBUG_MAIN << "basedir=" << m_basedir;
0323     KILE_DEBUG_MAIN << "workingDir=" << m_workingDir;
0324 }
0325 
0326 void Base::setTeXInputPaths(const QString& s)
0327 {
0328     m_texInputs = s;
0329 }
0330 
0331 QString Base::teXInputPaths() const
0332 {
0333     return m_texInputs;
0334 }
0335 
0336 void Base::setBibInputPaths(const QString& s)
0337 {
0338     m_bibInputs = s;
0339 }
0340 
0341 QString Base::bibInputPaths() const
0342 {
0343     return m_bibInputs;
0344 }
0345 
0346 void Base::setBstInputPaths(const QString& s)
0347 {
0348     m_bstInputs = s;
0349 }
0350 
0351 QString Base::bstInputPaths() const
0352 {
0353     return m_bstInputs;
0354 }
0355 
0356 void Base::copyPaths(Base* tool)
0357 {
0358     setTeXInputPaths(tool->teXInputPaths());
0359     setBibInputPaths(tool->bibInputPaths());
0360     setBstInputPaths(tool->bstInputPaths());
0361 }
0362 
0363 bool Base::determineTarget()
0364 {
0365     QFileInfo info(source());
0366 
0367     //if the target is not set previously, use the source filename
0368     if(m_target.isEmpty()) {
0369         //test for explicit override
0370         if (!readEntry("target").isEmpty()) {
0371             KILE_DEBUG_MAIN << "USING target SETTING";
0372             m_target = readEntry("target");
0373         }
0374         else if ( to().length() > 0) {
0375             m_target = S() + '.' + to();
0376         }
0377         else {
0378             m_target = source(false);
0379         }
0380     }
0381 
0382     if(m_relativedir.isEmpty() && (!readEntry("relDir").isEmpty())) {
0383         m_relativedir = readEntry("relDir");
0384     }
0385 
0386     QUrl url;
0387     if(!m_targetdir.isEmpty()) {
0388         url = QUrl::fromLocalFile(m_targetdir);
0389     }
0390     else if(!m_workingDir.isEmpty()) {
0391         url = QUrl::fromLocalFile(m_workingDir);
0392     }
0393     else {
0394         url = QUrl::fromLocalFile(m_basedir);
0395     }
0396     url = url.adjusted(QUrl::StripTrailingSlash);
0397     url.setPath(QDir::cleanPath(url.path() + '/' + m_relativedir));
0398     m_targetdir = url.toLocalFile();
0399 
0400     setTarget(m_target);
0401     setTargetDir(m_targetdir);
0402 
0403     KILE_DEBUG_MAIN << "==KileTool::Base::determineTarget()=========";
0404     KILE_DEBUG_MAIN << "\tm_targetdir=" << m_targetdir;
0405     KILE_DEBUG_MAIN << "\tm_target=" << m_target;
0406 
0407     return true;
0408 }
0409 
0410 bool Base::checkTarget()
0411 {
0412     //check if the target directory is accessible
0413     QFileInfo info(m_targetdir);
0414 
0415     if((flags() & NeedTargetDirExec ) && (!info.isExecutable())) {
0416         sendMessage(Error, msg(NeedTargetDirExec).subs(m_targetdir).toString());
0417         return false;
0418     }
0419 
0420     if((flags() & NeedTargetDirWrite) && (!info.isWritable())) {
0421         sendMessage(Error, msg(NeedTargetDirWrite).subs(m_targetdir).subs(m_name).toString());
0422         return false;
0423     }
0424 
0425     info.setFile(m_targetdir + '/' + m_target);
0426 
0427     if((flags() & NeedTargetExists) && (!info.exists())) {
0428         sendMessage(Error, msg(NeedTargetExists).subs(m_targetdir).subs(m_target).toString());
0429         return false;
0430     }
0431 
0432     if((flags() & NeedTargetRead) && (!info.isReadable())) {
0433         sendMessage(Error, msg(NeedTargetRead).subs(m_targetdir).subs(m_target).toString());
0434         return false;
0435     }
0436 
0437     return true;
0438 }
0439 
0440 void Base::setTarget(const QString &target)
0441 {
0442     m_target = target;
0443     addDict("%target", m_target);
0444 }
0445 
0446 void Base::setTargetDir(const QString &target)
0447 {
0448     m_targetdir = target;
0449     addDict("%dir_target", m_targetdir);
0450 }
0451 
0452 void Base::setTargetPath(const QString &target)
0453 {
0454     QFileInfo fi(target);
0455     setTarget(fi.fileName());
0456     setTargetDir(fi.absolutePath());
0457 }
0458 
0459 bool Base::checkPrereqs()
0460 {
0461     return true;
0462 }
0463 
0464 void Base::stop()
0465 {
0466     if (m_launcher) {
0467         m_launcher->kill();
0468     }
0469 
0470     emit(done(this, Aborted, m_childToolSpawned));
0471 }
0472 
0473 bool Base::finish(int result)
0474 {
0475     KILE_DEBUG_MAIN << "==KileTool::Base::finish()==============";
0476     if (sender())
0477     {
0478         KILE_DEBUG_MAIN << "\tcalled by " << sender()->objectName() << " " << sender()->metaObject()->className();
0479     }
0480 
0481     if ( result == Aborted )
0482         sendMessage(Error, "Aborted");
0483 
0484     if ( result == Success )
0485         sendMessage(Info,"Done!");
0486 
0487     KILE_DEBUG_MAIN << "\temitting done(KileTool::Base*, int) " << name();
0488     emit(done(this, result, m_childToolSpawned));
0489 
0490     //we will only get here if the done() signal is not connected to the manager (who will destroy this object)
0491     if (result == Success) {
0492         return true;
0493     }
0494     else {
0495         return false;
0496     }
0497 }
0498 
0499 void Base::installLaTeXOutputParserResult(int nErrors, int nWarnings, int nBadBoxes, const LatexOutputInfoArray& outputList,
0500         const QString& logFile)
0501 {
0502     m_nErrors = nErrors;
0503     m_nWarnings = nWarnings;
0504     m_nBadBoxes = nBadBoxes;
0505     m_latexOutputInfoList = outputList;
0506     m_logFile = logFile;
0507 
0508     latexOutputParserResultInstalled();
0509 }
0510 
0511 void Base::latexOutputParserResultInstalled()
0512 {
0513     finish(Success);
0514 }
0515 
0516 void Base::installLauncher(Launcher *lr)
0517 {
0518     if(m_launcher != lr)
0519         delete m_launcher;
0520 
0521     m_launcher = lr;
0522     //lr->setParamDict(paramDict());
0523     lr->setTool(this);
0524 
0525     connect(lr, SIGNAL(message(int,QString)), this, SLOT(sendMessage(int,QString)));
0526     connect(lr, SIGNAL(output(QString)), this, SLOT(filterOutput(QString)));
0527     connect(lr, SIGNAL(done(int)), this, SLOT(finish(int)));
0528 }
0529 
0530 bool Base::installLauncher()
0531 {
0532     if (m_launcher) {
0533         return true;
0534     }
0535 
0536     QString type = readEntry("type");
0537     KILE_DEBUG_MAIN << "installing launcher of type " << type;
0538     Launcher *lr = Q_NULLPTR;
0539 
0540     if ( type == "Process" ) {
0541         lr = new ProcessLauncher();
0542     }
0543     else if ( type == "Konsole" ) {
0544         lr = new KonsoleLauncher();
0545     }
0546     else if ( type == "DocumentViewer" ) {
0547         lr = new DocumentViewerLauncher();
0548     }
0549 
0550     if (lr) {
0551         installLauncher(lr);
0552         return true;
0553     }
0554     else {
0555         m_launcher = Q_NULLPTR;
0556         return false;
0557     }
0558 }
0559 
0560 void Base::setupAsChildTool(KileTool::Base *child)
0561 {
0562     Q_UNUSED(child);
0563 }
0564 
0565 void Base::sendMessage(int type, const QString &msg)
0566 {
0567     emit(message(type, msg, name()));
0568 }
0569 
0570 void Base::filterOutput(const QString & str)
0571 {
0572     //here you have the change to filter the output and do some error extraction for example
0573     //this should be done by a OutputFilter class
0574 
0575     //idea: store the buffer until a complete line (or more) has been received then parse these lines
0576     //just send the buf immediately to the output widget, the results of the parsing are displayed in
0577     //the log widget anyway.
0578     emit(output(str));
0579 }
0580 
0581 bool Base::addDict(const QString & key, const QString & value)
0582 {
0583     bool e = !(paramDict().contains(key));
0584     paramDict()[key] = value;
0585     return e;
0586 }
0587 
0588 bool Base::needsUpdate(const QString &target, const QString &source)
0589 {
0590     KILE_DEBUG_MAIN << "==Base::needsUpdate(" << target << "," << source;
0591     QFileInfo targetinfo(target);
0592     QFileInfo sourceinfo(source);
0593     QDateTime currDateTime = QDateTime::currentDateTime();
0594 
0595     if(!(sourceinfo.exists() && sourceinfo.isReadable())) {
0596         KILE_DEBUG_MAIN << "\treturning false: source does not exist";
0597         return false;
0598     }
0599 
0600     if(!targetinfo.exists()) {
0601         KILE_DEBUG_MAIN << "\treturning true: target does not exist";
0602         return true;
0603     }
0604 
0605     KILE_DEBUG_MAIN << "\ttarget: " << targetinfo.lastModified().toString();
0606     KILE_DEBUG_MAIN << "\tsource: " << sourceinfo.lastModified().toString();
0607 
0608     if(targetinfo.lastModified() > currDateTime) {
0609         KILE_DEBUG_MAIN << "targetinfo.lastModifiedTime() is in the future";
0610         return false;
0611     }
0612     else if(sourceinfo.lastModified() > currDateTime) {
0613         KILE_DEBUG_MAIN << "sourceinfo.lastModifiedTime() is in the future";
0614         return false;
0615     }
0616 
0617     KILE_DEBUG_MAIN << "\treturning " << (targetinfo.lastModified() < sourceinfo.lastModified());
0618     return targetinfo.lastModified() < sourceinfo.lastModified();
0619 }
0620 
0621 Compile::Compile(const QString &name, Manager * manager, bool prepare /*= true*/)
0622     : Base(name, manager, prepare)
0623 {
0624     setFlags( flags() | NeedTargetDirExec | NeedTargetDirWrite);
0625 }
0626 
0627 Compile::~Compile()
0628 {}
0629 
0630 bool Compile::checkSource()
0631 {
0632     if ( !Base::checkSource() ) return false;
0633 
0634     bool isRoot = true;
0635     KileDocument::TextInfo *docinfo = manager()->info()->docManager()->textInfoFor(source());
0636     if (docinfo) {
0637         isRoot = (readEntry("checkForRoot") == "yes") ? docinfo->isLaTeXRoot() : true;
0638     }
0639 
0640     if (!isRoot)
0641     {
0642         return  manager()->queryContinue(i18n("The document %1 is not a LaTeX root document; continue anyway?", source()), i18n("Continue?"));
0643     }
0644 
0645     return true;
0646 }
0647 
0648 View::View(const QString &name, Manager * manager, bool prepare /*= true*/)
0649     : Base(name, manager, prepare)
0650 {
0651     setFlags(NeedTargetDirExec | NeedTargetExists | NeedTargetRead);
0652 
0653     KILE_DEBUG_MAIN << "View: flag " << (flags() & NeedTargetExists);
0654     setMsg(NeedTargetExists, ki18n("The file %1/%2 does not exist; did you compile the source file?"));
0655 }
0656 
0657 View::~View()
0658 {
0659 }
0660 
0661 
0662 Archive::Archive(const QString &name, Manager * manager, bool prepare /* = true*/)
0663     : Base(name, manager,prepare)
0664 {
0665     setFlags( NeedTargetDirExec | NeedTargetDirWrite );
0666 }
0667 
0668 Archive::~Archive()
0669 {}
0670 
0671 bool Archive::checkPrereqs()
0672 {
0673     if(!m_project) {
0674         sendMessage(Error,i18n("The current document is not associated to a project. Please activate a document that is associated to the project you want to archive, then choose Archive again."));
0675         return false;
0676     }
0677     else if(m_fileList.isEmpty()) {
0678         sendMessage(Error, i18n("No files have been chosen for archiving."));
0679         return false;
0680     }
0681     else {
0682         return true;
0683     }
0684 }
0685 
0686 void Archive::setSource(const QString &source, const QString& workingDir)
0687 {
0688     Q_UNUSED(workingDir);
0689     QUrl url = QUrl::fromLocalFile(source);
0690     m_project = manager()->info()->docManager()->projectFor(url);
0691     if ( !m_project )
0692         m_project = manager()->info()->docManager()->activeProject();
0693     if ( !m_project )
0694         m_project = manager()->info()->docManager()->selectProject(i18n("Archive Project"));
0695     if ( !m_project )
0696     {
0697         Base::setSource(source);
0698         return;
0699     }
0700 
0701     manager()->info()->docManager()->projectSave(m_project);
0702     Base::setSource(m_project->url().toLocalFile());
0703     m_fileList = m_project->archiveFileList();
0704 
0705     addDict("%AFL", m_fileList);
0706 
0707     KILE_DEBUG_MAIN << "===KileTool::Archive::setSource("<< source << ")==============";
0708     KILE_DEBUG_MAIN << "m_fileList="<<m_fileList<< Qt::endl;
0709 }
0710 
0711 Convert::Convert(const QString &name, Manager * manager, bool prepare /*= true*/)
0712     : Base(name, manager,prepare)
0713 {
0714     setFlags( flags() | NeedTargetDirExec | NeedTargetDirWrite );
0715 }
0716 
0717 Convert::~Convert()
0718 {
0719 }
0720 
0721 bool Convert::determineSource()
0722 {
0723     bool  br = Base::determineSource();
0724     setSource(baseDir() + '/' + S() + '.' + from());
0725     return br;
0726 }
0727 
0728 Sequence::Sequence(const QString &name, Manager *manager, bool prepare /*= true*/)
0729     : Base(name, manager, prepare), m_latexOutputHandler(Q_NULLPTR)
0730 {
0731 }
0732 
0733 Sequence::~Sequence() {
0734     qDeleteAll(m_tools);
0735 }
0736 
0737 LaTeXOutputHandler* Sequence::latexOutputHandler()
0738 {
0739     return m_latexOutputHandler;
0740 }
0741 
0742 void Sequence::setLaTeXOutputHandler(LaTeXOutputHandler *h)
0743 {
0744     m_latexOutputHandler = h;
0745 }
0746 
0747 bool Sequence::determineSource()
0748 {
0749     QString src = source();
0750 
0751     // check whether the source has been set already
0752     if(!src.isEmpty()) {
0753         return true;
0754     }
0755 
0756     // the basedir is determined from the current compile target,
0757     // determined by getCompileName()
0758     LaTeXOutputHandler *h = Q_NULLPTR;
0759     src = m_ki->getCompileName(false, &h);
0760 
0761     setSource(src);
0762     setLaTeXOutputHandler(h);
0763 
0764     return true;
0765 }
0766 
0767 bool Sequence::requestSaveAll()
0768 {
0769     // if one of the tools in the sequence requests save-all, then we also
0770     // request it
0771     for(Base *tool : m_tools) {
0772         if(tool->requestSaveAll()) {
0773             return true;
0774         }
0775     }
0776 
0777     return false;
0778 }
0779 
0780 void Sequence::setupSequenceTools()
0781 {
0782     QStringList toolNameList = readEntry("sequence").split(',');
0783     QString tl, cfg;
0784     for(QStringList::iterator i = toolNameList.begin(); i != toolNameList.end(); ++i) {
0785         QString fullToolSpec = (*i).trimmed();
0786         extract(fullToolSpec, tl, cfg);
0787 
0788         Base *tool = manager()->createTool(tl, cfg, false); // create tool with delayed preparation
0789         if (tool) {
0790             KILE_DEBUG_MAIN << "===tool created with name " << tool->name();
0791             if(!(manager()->info()->watchFile() && tool->isViewer())) { // FIXME: why this?
0792                 KILE_DEBUG_MAIN << "\tqueueing " << tl << "(" << cfg << ") with " << source();
0793                 m_tools.push_back(tool);
0794             }
0795             else {
0796                 delete tool;
0797             }
0798         }
0799         else {
0800             m_unknownToolSpec = fullToolSpec;
0801             qDeleteAll(m_tools);
0802             m_tools.clear();
0803             return;
0804         }
0805     }
0806 }
0807 
0808 int Sequence::run()
0809 {
0810     KILE_DEBUG_MAIN << "==KileTool::Sequence::run()==================";
0811 
0812     determineSource();
0813     if (!checkSource()) {
0814         // tools in 'm_tools' will be deleted in the destructor
0815         return NoValidSource;
0816     }
0817 
0818     if(!m_unknownToolSpec.isEmpty()) {
0819         // 'm_tools' is empty
0820         sendMessage(Error, i18n("Unknown tool %1.", m_unknownToolSpec));
0821         emit(done(this, Failed, m_childToolSpawned));
0822         return ConfigureFailed;
0823     }
0824 
0825     for(Base *tool : m_tools) {
0826         tool->setSource(source());
0827 
0828         // if we are running a 'LaTeX' tool here, we still have to set the
0829         // appropriate LaTeXOutputHandler
0830         {
0831             LaTeX *latex = dynamic_cast<LaTeX*>(tool);
0832             if(latex && m_latexOutputHandler) {
0833                 latex->setLaTeXOutputHandler(m_latexOutputHandler);
0834             }
0835         }
0836 
0837         manager()->run(tool);
0838     }
0839 
0840     m_tools.clear(); // the tools will be deleted by the tool manager from now on
0841     emit(done(this, Silent, m_childToolSpawned));
0842 
0843     return Success;
0844 }
0845 }
0846