File indexing completed on 2024-04-28 13:00:49
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