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

0001 /**************************************************************************************
0002   Copyright (C) 2003 by Jeroen Wijnhout (Jeroen.Wijnhout@kdemail.net)
0003                 2011-2018 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 "kiletoolmanager.h"
0016 
0017 #include <algorithm>
0018 
0019 #include <QFileInfo>
0020 #include <QMenu>
0021 #include <QRegExp>
0022 #include <QTimer>
0023 
0024 #include <KActionCollection>
0025 #include <KConfig>
0026 #include <KLocalizedString>
0027 #include <KMessageBox>
0028 #include <KParts/PartManager>
0029 #include <KSelectAction>
0030 
0031 #include "configurationmanager.h"
0032 #include "errorhandler.h"
0033 #include "kileconfig.h"
0034 #include "kiledebug.h"
0035 #include "kiledocmanager.h"
0036 #include "kileinfo.h"
0037 #include "kileproject.h"
0038 #include "kilestdtools.h"
0039 #include "kiletool_enums.h"
0040 #include "parser/parsermanager.h"
0041 #include "widgets/logwidget.h"
0042 #include "widgets/outputview.h"
0043 #include "widgets/sidebar.h"
0044 
0045 namespace KileTool
0046 {
0047 QueueItem::QueueItem(Base *tool, bool block) : m_tool(tool), m_bBlock(block)
0048 {
0049 }
0050 
0051 QueueItem::~QueueItem()
0052 {
0053 }
0054 
0055 Base* Queue::tool() const
0056 {
0057     if(count() > 0 && head()) {
0058         return head()->tool();
0059     }
0060     else {
0061         return 0;
0062     }
0063 }
0064 
0065 bool Queue::shouldBlock() const
0066 {
0067     if(count() > 0 && head()) {
0068         return head()->shouldBlock();
0069     }
0070     else {
0071         return false;
0072     }
0073 }
0074 
0075 void Queue::enqueueNext(QueueItem *item)
0076 {
0077     if(count() < 2) {
0078         enqueue(item);
0079     }
0080     else {
0081         QueueItem *headitem = dequeue();
0082         Queue *oldqueue = new Queue(*this);
0083 
0084         clear();
0085         KILE_DEBUG_MAIN << "\tenqueueing: " << headitem->tool()->name() << Qt::endl;
0086         enqueue(headitem);
0087         KILE_DEBUG_MAIN << "\tenqueueing: " << item->tool()->name() << Qt::endl;
0088         enqueue(item);
0089         while(!oldqueue->isEmpty()) {
0090             KILE_DEBUG_MAIN << "\tenqueueing: " << oldqueue->head()->tool()->name() << Qt::endl;
0091             enqueue(oldqueue->dequeue());
0092         }
0093     }
0094 }
0095 
0096 Manager::Manager(KileInfo *ki, KConfig *config, KileWidget::OutputView *output, QStackedWidget *stack, uint to, KActionCollection *ac) :
0097     m_ki(ki),
0098     m_config(config),
0099     m_output(output),
0100     m_stack(stack),
0101     m_stopAction(Q_NULLPTR),
0102     m_bClear(true),
0103     m_nLastResult(Success),
0104     m_nTimeout(to),
0105     m_bibliographyBackendSelectAction(Q_NULLPTR)
0106 {
0107     connect(m_ki->parserManager(), SIGNAL(documentParsingComplete()), this, SLOT(handleDocumentParsingComplete()));
0108 
0109     connect(this, SIGNAL(childToolSpawned(KileTool::Base*,KileTool::Base*)),
0110             m_ki->errorHandler(), SLOT(handleSpawnedChildTool(KileTool::Base*,KileTool::Base*)));
0111 
0112     m_timer = new QTimer(this);
0113     connect(m_timer, SIGNAL(timeout()), this, SLOT(enableClear()));
0114 
0115     connect(m_ki->errorHandler(), SIGNAL(currentLaTeXOutputHandlerChanged(LaTeXOutputHandler*)), SLOT(currentLaTeXOutputHandlerChanged(LaTeXOutputHandler*)));
0116 
0117     //create actions must be invoked before buildBibliographyBackendSelection()!
0118     createActions(ac);
0119     buildBibliographyBackendSelection();
0120 
0121     connect(m_ki->configurationManager(), SIGNAL(configChanged()), SLOT(buildBibliographyBackendSelection()));
0122 }
0123 
0124 Manager::~Manager()
0125 {
0126     KILE_DEBUG_MAIN;
0127 
0128     for(QQueue<QueueItem*>::iterator i = m_queue.begin(); i != m_queue.end(); ++i) {
0129         // this will also stop any running processes
0130         delete (*i)->tool();
0131         delete (*i);
0132     }
0133     // tools have the tool manager as parent; so, all remaining tools will be deleted
0134     // after this, i.e. those that were scheduled for deletion via 'deleteLater' but
0135     // are no longer member of the queue
0136 }
0137 
0138 bool Manager::shouldBlock()
0139 {
0140     return m_queue.shouldBlock();
0141 }
0142 
0143 // in some cases the pointer m_stopAction might not be valid, therefore this helper function comes in handy
0144 void Manager::setEnabledStopButton(bool state) {
0145 
0146     if(m_stopAction) {
0147         m_stopAction->setEnabled(state);
0148     }
0149 }
0150 
0151 void Manager::enableClear()
0152 {
0153     m_bClear = true;
0154 }
0155 
0156 bool Manager::queryContinue(const QString & question, const QString & caption /*= QString()*/)
0157 {
0158     return (KMessageBox::warningContinueCancel(m_stack, question, caption, KStandardGuiItem::cont(), KStandardGuiItem::cancel(), "showNotALaTeXRootDocumentWarning") == KMessageBox::Continue);
0159 }
0160 
0161 void Manager::run(Base *tool)
0162 {
0163     // if the tool requests a save-all operation, we wait for the parsing to
0164     // be finished before launching it
0165     if(!tool->requestSaveAll() || m_ki->parserManager()->isDocumentParsingComplete()) {
0166         // parsing done, we can start the tool immediately
0167         runImmediately(tool);
0168         return;
0169     }
0170     connect(tool, SIGNAL(aboutToBeDestroyed(KileTool::Base*)),
0171             this, SLOT(toolScheduledAfterParsingDestroyed(KileTool::Base*)), Qt::UniqueConnection);
0172     if(!m_toolsScheduledAfterParsingList.contains(tool)) {
0173         m_toolsScheduledAfterParsingList.push_back(tool);
0174     }
0175 }
0176 
0177 void Manager::toolScheduledAfterParsingDestroyed(KileTool::Base *tool)
0178 {
0179     m_toolsScheduledAfterParsingList.removeAll(tool);
0180 }
0181 
0182 void Manager::handleDocumentParsingComplete()
0183 {
0184     for(Base *tool : m_toolsScheduledAfterParsingList) {
0185         disconnect(tool, SIGNAL(aboutToBeDestroyed(KileTool::Base*)),
0186                    this, SLOT(toolScheduledAfterParsingDestroyed(KileTool::Base*)));
0187         runImmediately(tool);
0188     }
0189     m_toolsScheduledAfterParsingList.clear();
0190 }
0191 
0192 int Manager::runImmediately(Base *tool, bool insertNext /*= false*/, bool block /*= false*/, Base *parent /*= Q_NULLPTR*/)
0193 {
0194     KILE_DEBUG_MAIN << "==KileTool::Manager::runImmediately(Base *)============" << Qt::endl;
0195     if(m_bClear && (m_queue.count() == 0)) {
0196         m_ki->errorHandler()->clearMessages();
0197         m_output->clear();
0198     }
0199 
0200     if(dynamic_cast<KileTool::LaTeX*>(tool)) {
0201         connect(tool, SIGNAL(done(KileTool::Base*,int,bool)),
0202                 m_ki->errorHandler(), SLOT(handleLaTeXToolDone(KileTool::Base*,int,bool)));
0203     }
0204 
0205     if(tool->needsToBePrepared()) {
0206         tool->prepareToRun();
0207     }
0208 
0209     //FIXME: shouldn't restart timer if a Sequence command takes longer than the 10 secs
0210     //restart timer, so we only clear the logs if a tool is started after 10 sec.
0211     m_bClear = false;
0212     m_timer->start(m_nTimeout);
0213 
0214     if(insertNext) {
0215         m_queue.enqueueNext(new QueueItem(tool, block));
0216     }
0217     else {
0218         m_queue.enqueue(new QueueItem(tool, block));
0219     }
0220 
0221     if(parent) {
0222         emit(childToolSpawned(parent,tool));
0223     }
0224 
0225     KILE_DEBUG_MAIN << "\tin queue: " << m_queue.count() << Qt::endl;
0226     if(m_queue.count() == 1) {
0227         return runNextInQueue();
0228     }
0229     else if(m_queue.count() > 1) {
0230         return Running;
0231     }
0232     else {
0233         return ConfigureFailed;
0234     }
0235 }
0236 
0237 int Manager::runChildNext(Base *parent, Base *tool, bool block /*= false*/)
0238 {
0239     parent->setupAsChildTool(tool);
0240 
0241     return runImmediately(tool, true, block, parent);
0242 }
0243 
0244 int Manager::runNextInQueue()
0245 {
0246     Base *head = m_queue.tool();
0247     if(head) {
0248         if (m_ki->errorHandler()->areMessagesShown()) {
0249             m_ki->errorHandler()->addEmptyLineToMessages();
0250         }
0251 
0252         if(!head->isPrepared()) {
0253             head->prepareToRun();
0254         }
0255 
0256         int status;
0257         if((status=head->run()) != Running) { //tool did not even start, clear queue
0258             stop();
0259             for(QQueue<QueueItem*>::iterator i = m_queue.begin(); i != m_queue.end(); ++i) {
0260                 (*i)->tool()->deleteLater();
0261                 delete (*i);
0262             }
0263             m_queue.clear();
0264             return status;
0265         }
0266 
0267         m_ki->errorHandler()->startToolLogOutput();
0268         emit(toolStarted());
0269 
0270         return Running;
0271     }
0272 
0273     return ConfigureFailed;
0274 }
0275 
0276 Base* Manager::createTool(const QString& name, const QString &cfg, bool prepare)
0277 {
0278     if(!m_factory) {
0279         m_ki->errorHandler()->printMessage(Error, i18n("No factory installed, contact the author of Kile."));
0280         return Q_NULLPTR;
0281     }
0282 
0283     Base* pTool = m_factory->create(name, cfg, prepare);
0284     if(!pTool) {
0285         m_ki->errorHandler()->printMessage(Error, i18n("Unknown tool %1.", name));
0286         return Q_NULLPTR;
0287     }
0288     initTool(pTool);
0289     return pTool;
0290 }
0291 
0292 void Manager::initTool(Base *tool)
0293 {
0294     tool->setInfo(m_ki);
0295     tool->setConfig(m_config);
0296 
0297     connect(tool, SIGNAL(message(int,QString,QString)), m_ki->errorHandler(), SLOT(printMessage(int,QString,QString)));
0298     connect(tool, SIGNAL(output(QString)), m_output, SLOT(receive(QString)));
0299     connect(tool, SIGNAL(done(KileTool::Base*,int,bool)), this, SLOT(done(KileTool::Base*,int)));
0300     connect(tool, SIGNAL(start(KileTool::Base*)), this, SLOT(started(KileTool::Base*)));
0301 }
0302 
0303 void Manager::started(Base *tool)
0304 {
0305     KILE_DEBUG_MAIN << "STARTING tool: " << tool->name() << Qt::endl;
0306     setEnabledStopButton(true);
0307 
0308     if (tool->isViewer()) {
0309         if(tool == m_queue.tool()) {
0310             m_queue.dequeue();
0311         }
0312         setEnabledStopButton(false);
0313         QTimer::singleShot(100, this, SLOT(runNextInQueue()));
0314     }
0315 }
0316 
0317 void Manager::stop()
0318 {
0319     setEnabledStopButton(false);
0320     if(m_queue.tool()) {
0321         m_queue.tool()->stop();
0322     }
0323 }
0324 
0325 void Manager::stopLivePreview()
0326 {
0327     KILE_DEBUG_MAIN;
0328 
0329     Base *tool = m_queue.tool();
0330 
0331     if(tool && tool->isPartOfLivePreview()) {
0332         setEnabledStopButton(false);
0333         tool->stop();
0334     }
0335 
0336     deleteLivePreviewToolsFromQueue();
0337     deleteLivePreviewToolsFromRunningAfterParsingQueue();
0338 }
0339 
0340 void Manager::stopActionDestroyed()
0341 {
0342     m_stopAction = Q_NULLPTR;
0343 }
0344 
0345 void Manager::done(KileTool::Base *tool, int result)
0346 {
0347     setEnabledStopButton(false);
0348     m_nLastResult = result;
0349 
0350     m_ki->errorHandler()->endToolLogOutput();
0351 
0352     if(tool != m_queue.tool()) { //oops, tool finished async, could happen with view tools
0353         tool->deleteLater();
0354         return;
0355     }
0356 
0357     QueueItem *item = m_queue.dequeue();
0358     item->tool()->deleteLater();
0359     delete item;
0360 
0361     if(result == Aborted) {
0362         tool->sendMessage(Error, i18n("Aborted"));
0363     }
0364 
0365     if(result != Success && result != Silent) { //abort execution, delete all remaining tools
0366         if(tool->isPartOfLivePreview()) { // live preview was stopped / aborted
0367             deleteLivePreviewToolsFromQueue();
0368             // don't forget to run non-live preview tools that are pending
0369             runNextInQueue();
0370         }
0371         else {
0372             for(QQueue<QueueItem*>::iterator i = m_queue.begin(); i != m_queue.end(); ++i) {
0373                 (*i)->tool()->deleteLater();
0374                 delete (*i);
0375             }
0376             m_queue.clear();
0377             m_ki->focusLog();
0378         }
0379     }
0380     else { //continue
0381         runNextInQueue();
0382     }
0383 }
0384 
0385 void Manager::deleteLivePreviewToolsFromQueue()
0386 {
0387     for(QQueue<QueueItem*>::iterator i = m_queue.begin(); i != m_queue.end();) {
0388         QueueItem *item = *i;
0389         if(item->tool()->isPartOfLivePreview()) {
0390             i = m_queue.erase(i);
0391             item->tool()->deleteLater();
0392             delete item;
0393         }
0394         else {
0395             ++i;
0396         }
0397     }
0398 }
0399 
0400 void Manager::deleteLivePreviewToolsFromRunningAfterParsingQueue()
0401 {
0402     for(QQueue<Base*>::iterator i = m_toolsScheduledAfterParsingList.begin(); i != m_toolsScheduledAfterParsingList.end();) {
0403         Base *tool = *i;
0404         if(tool->isPartOfLivePreview()) {
0405             i = m_toolsScheduledAfterParsingList.erase(i);
0406             delete tool;
0407         }
0408         else {
0409             ++i;
0410         }
0411     }
0412 }
0413 
0414 QString Manager::currentGroup(const QString &name, bool usequeue, bool useproject)
0415 {
0416     if (useproject) {
0417         KileProject *project = m_ki->docManager()->activeProject();
0418         if(project) {
0419             QString cfg = configName(name, dynamic_cast<KConfig*>(project->config()));
0420             if(cfg.length() > 0) {
0421                 return groupFor(name, cfg);
0422             }
0423         }
0424     }
0425     if(usequeue && !m_queue.isEmpty() && m_queue.tool() && (m_queue.tool()->name() == name) && (!m_queue.tool()->toolConfig().isEmpty())) {
0426         return groupFor(name, m_queue.tool()->toolConfig());
0427     }
0428     else {
0429         return groupFor(name, m_config);
0430     }
0431 }
0432 
0433 bool Manager::retrieveEntryMap(const QString & name, Config & map, bool usequeue, bool useproject, const QString & cfg /*= QString()*/)
0434 {
0435     QString group = (cfg.isEmpty()) ? currentGroup(name, usequeue, useproject) : groupFor(name, cfg);
0436 
0437     KILE_DEBUG_MAIN << "==KileTool::Manager::retrieveEntryMap=============" << Qt::endl;
0438     KILE_DEBUG_MAIN << "\t" << name << " => " << group << Qt::endl;
0439     if(m_config->hasGroup(group)) {
0440         map = m_config->entryMap(group);
0441 
0442         //use project overrides
0443         KileProject *project = m_ki->docManager()->activeProject();
0444         if(useproject && project) {
0445             KConfig *prjcfg = dynamic_cast<KConfig*>(project->config());
0446             if(prjcfg) {
0447                 QString grp = groupFor(name, prjcfg);
0448                 Config prjmap = prjcfg->entryMap(grp);
0449                 for (Config::Iterator it  = prjmap.begin(); it != prjmap.end(); ++it) {
0450                     map[it.key()] = it.value();
0451                 }
0452             }
0453         }
0454     }
0455     else {
0456         return false;
0457     }
0458 
0459     return true;
0460 }
0461 
0462 void Manager::saveEntryMap(const QString & name, Config & map, bool usequeue, bool useproject)
0463 {
0464     KILE_DEBUG_MAIN << "==KileTool::Manager::saveEntryMap=============" << Qt::endl;
0465     QString group = currentGroup(name, usequeue, useproject);
0466     KILE_DEBUG_MAIN << "\t" << name << " => " << group << Qt::endl;
0467     KConfigGroup configGroup = m_config->group(group);
0468 
0469     Config::Iterator it;
0470     for(it = map.begin() ; it != map.end(); ++it) {
0471         if(!it.value().isEmpty()) {
0472             configGroup.writeEntry(it.key(), it.value());
0473         }
0474     }
0475 }
0476 
0477 bool Manager::configure(Base *tool, const QString& cfg /* = QString() */)
0478 {
0479     KILE_DEBUG_MAIN << "==KileTool::Manager::configure()===============" << Qt::endl;
0480     //configure the tool
0481 
0482     Config map;
0483 
0484     if(!retrieveEntryMap(tool->name(), map, true, true, cfg)) {
0485         QString group = (cfg.isEmpty()) ? currentGroup(tool->name(), true, true) : groupFor(tool->name(), cfg);
0486         m_ki->errorHandler()->printMessage(Error, i18n("Cannot find the tool \"%1\" in the configuration database.", group));
0487         return false;
0488     }
0489 
0490     tool->setEntryMap(map);
0491 
0492     return true;
0493 }
0494 
0495 void Manager::wantGUIState(const QString & state)
0496 {
0497     KILE_DEBUG_MAIN << "REQUESTED state: " << state << Qt::endl;
0498     emit(requestGUIState(state));
0499 }
0500 
0501 KileView::Manager* Manager::viewManager()
0502 {
0503     return m_ki->viewManager();
0504 }
0505 
0506 KileTool::LivePreviewManager* Manager::livePreviewManager()
0507 {
0508     return m_ki->livePreviewManager();
0509 }
0510 
0511 KileParser::Manager* Manager::parserManager()
0512 {
0513     return m_ki->parserManager();
0514 }
0515 
0516 QStringList toolList(KConfig *config, bool menuOnly)
0517 {
0518     KILE_DEBUG_MAIN << "==KileTool::toolList()==================" << Qt::endl;
0519 
0520     const QStringList groups = config->groupList();
0521     QStringList tools;
0522 
0523     QRegExp re = QRegExp("Tool/(.+)/.+");
0524     QString name;
0525 
0526     for (const auto& group : groups) {
0527         if(!config->hasGroup(group)) { // 'group' might have been deleted
0528             continue;                // work around bug 384039
0529         }
0530         if(re.exactMatch(group)) {
0531             name = configName(re.cap(1), config);
0532 
0533             if(name.isEmpty() || !group.endsWith(name)) {
0534                 continue;
0535             }
0536 
0537             if((!menuOnly) || (menuFor(re.cap(1), config) != "none")) {
0538                 tools.append(re.cap(1));
0539             }
0540         }
0541     }
0542 
0543     tools.sort();
0544 //      KILE_DEBUG_MAIN << "tools " << tools.join(", ");
0545 
0546     return tools;
0547 }
0548 
0549 QList<ToolConfigPair> toolsWithConfigurationsBasedOnClass(KConfig *config, const QString& className)
0550 {
0551     const QStringList groups = config->groupList();
0552 
0553     QRegExp re = QRegExp("Tool/(.+)/(.+)");
0554     QList<ToolConfigPair> toReturn;
0555 
0556     for (const auto& group : groups) {
0557         if(!config->hasGroup(group)) { // 'group' might have been deleted
0558             continue;                // work around bug 384039
0559         }
0560         if(re.exactMatch(group)) {
0561             const QString toolName = re.cap(1);
0562             const QString configName = re.cap(2);
0563 
0564             if(toolName.isEmpty()) {
0565                 continue;
0566             }
0567 
0568             if(config->group(group).readEntry("class", "") == className) {
0569                 toReturn.push_back(ToolConfigPair(toolName, configName));
0570             }
0571         }
0572     }
0573 
0574     return toReturn;
0575 }
0576 
0577 QString configName(const QString & tool, KConfig *config)
0578 {
0579     return config->group("Tools").readEntry(tool, QString());
0580 }
0581 
0582 void Manager::setConfigName(const QString &tool, const QString &name)
0583 {
0584     KileTool::setConfigName(tool, name, m_config);
0585 }
0586 
0587 void setConfigName(const QString &tool, const QString &name, KConfig *config)
0588 {
0589     KILE_DEBUG_MAIN << "==KileTool::Manager::setConfigName(" << tool << "," << name << ")===============" << Qt::endl;
0590     config->group("Tools").writeEntry(tool, name);
0591 }
0592 
0593 QString groupFor(const QString &tool, KConfig *config)
0594 {
0595     return groupFor(tool, configName(tool, config));
0596 }
0597 
0598 QString groupFor(const QString& tool, const QString& cfg /* = Default */ )
0599 {
0600     QString group = "Tool/" + tool + '/' + cfg;
0601     KILE_DEBUG_MAIN << "groupFor(const QString &" << tool << ", const QString & " << cfg << " ) = " << group;
0602     return group;
0603 }
0604 
0605 void extract(const QString &str, QString &tool, QString &cfg)
0606 {
0607     static QRegExp re("([^\\(]*)\\((.*)\\)");
0608     QString lcl = str.trimmed();
0609     cfg.clear();
0610     if(re.exactMatch(lcl)) {
0611         tool = re.cap(1).trimmed();
0612         cfg = re.cap(2).trimmed();
0613     }
0614     else {
0615         tool = lcl;
0616     }
0617     KILE_DEBUG_MAIN << "===void extract(const QString &str = " << str << " , QString &tool = " << tool << ", QString &cfg = " << cfg << " )===" << Qt::endl;
0618 }
0619 
0620 QString format(const QString & tool, const QString &cfg)
0621 {
0622     if (!cfg.isEmpty()) {
0623         return tool + '(' + cfg + ')';
0624     }
0625     else {
0626         return tool;
0627     }
0628 }
0629 
0630 QStringList configNames(const QString &tool, KConfig *config)
0631 {
0632     const QStringList groups = config->groupList();
0633     QStringList configs;
0634 
0635     QRegExp re = QRegExp("Tool/"+ tool +"/(.+)");
0636 
0637     for (const auto& group : groups) {
0638         if(!config->hasGroup(group)) { // 'group' might have been deleted
0639             continue;                // work around bug 384039
0640         }
0641         if(re.exactMatch(group)) {
0642             configs.append(re.cap(1));
0643         }
0644     }
0645 
0646     return configs;
0647 }
0648 
0649 QString commandFor(const QString& toolName, const QString& configName, KConfig *config)
0650 {
0651     return config->group(groupFor(toolName, configName)).readEntry("command", "");
0652 }
0653 
0654 QString menuFor(const QString &tool, KConfig *config)
0655 {
0656     return config->group("ToolsGUI").readEntry(tool, "Other,application-x-executable").section(',', 0, 0);
0657 }
0658 
0659 QString iconFor(const QString &tool, KConfig *config)
0660 {
0661     return config->group("ToolsGUI").readEntry(tool, "Other,application-x-executable").section(',', 1, 1);
0662 }
0663 
0664 void setGUIOptions(const QString &tool, const QString &menu, const QString &icon, KConfig *config)
0665 {
0666     QString entry = menu + ',' + icon;
0667 
0668     config->group("ToolsGUI").writeEntry(tool, entry);
0669 }
0670 
0671 QString categoryFor(const QString &clss)
0672 {
0673     if(clss == "Compile" || clss == "LaTeX") {
0674         return "Compile";
0675     }
0676     if(clss == "Convert") {
0677         return "Convert";
0678     }
0679     if(clss == "View" || clss == "ViewBib" || clss == "ViewHTML" || clss == "ForwardDVI") {
0680         return "View";
0681     }
0682     if(clss == "Sequence") {
0683         return "Sequence";
0684     }
0685     if(clss == "Archive") {
0686         return "Archive";
0687     }
0688 
0689     return "Base";
0690 }
0691 }
0692 
0693 bool KileTool::Manager::containsBibliographyTool(const ToolConfigPair& p) const
0694 {
0695     return m_bibliographyToolsList.contains(p);
0696 }
0697 
0698 KileTool::ToolConfigPair KileTool::Manager::findFirstBibliographyToolForCommand(const QString& command) const
0699 {
0700     // for now we will just select the first suitable tool
0701     for(const KileTool::ToolConfigPair& tool : m_bibliographyToolsList) {
0702         const QString toolCommand = commandFor(tool, m_config);
0703         if (QString::compare(command, toolCommand, Qt::CaseInsensitive) == 0) {
0704             return tool;
0705         }
0706     }
0707 
0708     return KileTool::ToolConfigPair();
0709 }
0710 
0711 void KileTool::Manager::buildBibliographyBackendSelection()
0712 {
0713     m_bibliographyBackendSelectAction->removeAllActions();
0714     m_bibliographyBackendSelectAction->menu()->clear();
0715     for(QMap<ToolConfigPair, QAction *>::iterator i = m_bibliographyBackendActionMap.begin(); i != m_bibliographyBackendActionMap.end(); ++i) {
0716         delete i.value();
0717     }
0718     m_bibliographyBackendActionMap.clear();
0719     m_bibliographyToolsList.clear();
0720 
0721     m_bibliographyBackendSelectAction->addAction(m_bibliographyBackendAutodetectAction);
0722 
0723     m_bibliographyToolsList = toolsWithConfigurationsBasedOnClass(m_config, BibliographyCompile::ToolClass);
0724     std::sort(m_bibliographyToolsList.begin(), m_bibliographyToolsList.end()); // necessary for the user-visible actions in the menu bar
0725 
0726     for(const ToolConfigPair& tool : m_bibliographyToolsList) {
0727         // create an action for backend selection
0728         QAction * action = m_bibliographyBackendSelectAction->addAction(tool.userStringRepresentation());
0729         action->setData(QVariant::fromValue(tool));
0730         m_bibliographyBackendActionMap[tool] = action;
0731     }
0732 
0733     m_bibliographyBackendSelectAction->menu()->addSeparator();
0734     m_bibliographyBackendSelectAction->menu()->addAction(m_bibliographyBackendResetAutodetectedAction);
0735 
0736     currentLaTeXOutputHandlerChanged(m_ki->findCurrentLaTeXOutputHandler());
0737 }
0738 
0739 void KileTool::Manager::createActions(KActionCollection *ac)
0740 {
0741     m_stopAction = new QAction(this);
0742     m_stopAction->setText(i18n("&Stop"));
0743     ac->addAction(QLatin1String("Stop"), m_stopAction);
0744     ac->setDefaultShortcut(m_stopAction, QKeySequence(Qt::Key_Escape));
0745     m_stopAction->setIcon(QIcon::fromTheme(QLatin1String("process-stop")));
0746     m_stopAction->setEnabled(false);
0747     connect(m_stopAction, &QAction::triggered, this, &KileTool::Manager::stop);
0748 
0749     delete m_bibliographyBackendSelectAction;
0750 
0751     m_bibliographyBackendSelectAction = new KSelectAction(i18n("Bibliography Back End"), this);
0752     m_bibliographyBackendAutodetectAction = m_bibliographyBackendSelectAction->addAction(i18n("Auto-Detect"));
0753     m_bibliographyBackendAutodetectAction->setStatusTip(i18n("Auto-detect the bibliography back end from LaTeX output"));
0754     m_bibliographyBackendSelectAction->setChecked(false);
0755 
0756     ac->addAction("bibbackend_select", m_bibliographyBackendSelectAction);
0757 
0758     m_bibliographyBackendResetAutodetectedAction = new QAction(i18n("Reset Auto-Detected Back End"), this);
0759     m_bibliographyBackendResetAutodetectedAction->setEnabled(false);
0760 
0761     connect(m_bibliographyBackendSelectAction, SIGNAL(triggered(QAction*)), SLOT(bibliographyBackendSelectedByUser()));
0762     connect(m_bibliographyBackendResetAutodetectedAction, SIGNAL(triggered(bool)), SLOT(resetAutodetectedBibliographyBackend()));
0763     connect(m_bibliographyBackendAutodetectAction, SIGNAL(toggled(bool)),
0764             m_bibliographyBackendResetAutodetectedAction, SLOT(setEnabled(bool)));
0765 }
0766 
0767 
0768 void KileTool::Manager::bibliographyBackendSelectedByUser()
0769 {
0770     LaTeXOutputHandler* h = m_ki->findCurrentLaTeXOutputHandler();
0771     QAction* currentBackendAction = m_bibliographyBackendSelectAction->currentAction();
0772 
0773     if (currentBackendAction == m_bibliographyBackendAutodetectAction) {
0774         h->setBibliographyBackendToolUserOverride(ToolConfigPair());
0775     }
0776     else {
0777         //here we do not need to check existence of tool
0778         h->setBibliographyBackendToolUserOverride(currentBackendAction->data().value<KileTool::ToolConfigPair>());
0779         h->setBibliographyBackendToolAutoDetected(ToolConfigPair());
0780     }
0781 }
0782 
0783 void KileTool::Manager::currentLaTeXOutputHandlerChanged(LaTeXOutputHandler* handler)
0784 {
0785     if(!handler) {
0786         m_bibliographyBackendSelectAction->setEnabled(false);
0787         return;
0788     }
0789 
0790     m_bibliographyBackendSelectAction->setEnabled(true);
0791 
0792     if (!m_bibliographyBackendActionMap.empty()) {
0793         ToolConfigPair userOverrideBibBackend = handler->bibliographyBackendToolUserOverride();
0794         if(!userOverrideBibBackend.isValid()) {
0795             m_bibliographyBackendAutodetectAction->setChecked(true);
0796         }
0797         else {
0798             // here we have to check whether the action exists
0799             QMap<ToolConfigPair, QAction *>::const_iterator i = m_bibliographyBackendActionMap.constFind(userOverrideBibBackend);
0800             if (i != m_bibliographyBackendActionMap.constEnd()) {
0801                 i.value()->setChecked(true);
0802             }
0803             else {
0804                 // the user previously selected a bibtool backend which is (no longer) present - let's use autodetection;
0805                 // this is done analogously in 'LaTeX::determineBibliographyBackend'
0806                 m_bibliographyBackendAutodetectAction->setChecked(true);
0807             }
0808         }
0809     }
0810     else {
0811         m_bibliographyBackendAutodetectAction->setChecked(true);
0812     }
0813 }
0814 
0815 void KileTool::Manager::resetAutodetectedBibliographyBackend()
0816 {
0817     LaTeXOutputHandler* h = m_ki->findCurrentLaTeXOutputHandler();
0818     if (h) {
0819         h->setBibliographyBackendToolAutoDetected(ToolConfigPair());
0820     }
0821 }
0822