File indexing completed on 2024-04-28 08:27:07
0001 /* This file is part of KDevelop 0002 0003 Copyright 2016 Anton Anikin <anton.anikin@htower.ru> 0004 0005 This program is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU General Public 0007 License as published by the Free Software Foundation; either 0008 version 2 of the License, or (at your option) any later version. 0009 0010 This program is distributed in the hope that it will be useful, 0011 but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 General Public License for more details. 0014 0015 You should have received a copy of the GNU General Public License 0016 along with this program; see the file COPYING. If not, write to 0017 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0018 Boston, MA 02110-1301, USA. 0019 */ 0020 0021 #include "plugin.h" 0022 0023 #include "config/globalconfigpage.h" 0024 #include "config/projectconfigpage.h" 0025 #include "debug.h" 0026 #include "problemmodel.h" 0027 #include "rules.h" 0028 #include "utils.h" 0029 0030 #include <interfaces/contextmenuextension.h> 0031 #include <interfaces/icore.h> 0032 #include <interfaces/idocumentcontroller.h> 0033 #include <interfaces/iprojectcontroller.h> 0034 #include <interfaces/iruncontroller.h> 0035 #include <interfaces/iuicontroller.h> 0036 #include <kactioncollection.h> 0037 #include <kmessagebox.h> 0038 #include <kpluginfactory.h> 0039 #include <language/interfaces/editorcontext.h> 0040 #include <project/projectconfigpage.h> 0041 #include <project/projectmodel.h> 0042 #include <util/jobstatus.h> 0043 0044 #include <QApplication> 0045 #include <QFile> 0046 0047 K_PLUGIN_FACTORY_WITH_JSON(VerappFactory, "kdevverapp.json", registerPlugin<verapp::Plugin>();) 0048 0049 namespace verapp 0050 { 0051 0052 Plugin::Plugin(QObject* parent, const QVariantList&) 0053 : IPlugin("kdevverapp", parent) 0054 , m_job(nullptr) 0055 , m_project(nullptr) 0056 , m_model(new ProblemModel(this)) 0057 { 0058 qCDebug(KDEV_VERAPP) << "setting kdevverapp.rc file"; 0059 setXMLFile("kdevverapp.rc"); 0060 0061 rules::init(); 0062 0063 m_menuActionFile = new QAction(i18n("Analyze Current File with Vera++"), this); 0064 connect(m_menuActionFile, &QAction::triggered, [this](){ 0065 runVerapp(false); 0066 }); 0067 actionCollection()->addAction("verapp_file", m_menuActionFile); 0068 0069 m_contextActionFile = new QAction(i18n("Vera++"), this); 0070 connect(m_contextActionFile, &QAction::triggered, [this]() { 0071 runVerapp(false); 0072 }); 0073 0074 m_menuActionProject = new QAction(i18n("Analyze Current Project with Vera++"), this); 0075 connect(m_menuActionProject, &QAction::triggered, [this](){ 0076 runVerapp(true); 0077 }); 0078 actionCollection()->addAction("verapp_project", m_menuActionProject); 0079 0080 m_contextActionProject = new QAction(i18n("Vera++"), this); 0081 connect(m_contextActionProject, &QAction::triggered, [this]() { 0082 runVerapp(true); 0083 }); 0084 0085 m_contextActionProjectItem = new QAction("Vera++", this); 0086 0087 connect(core()->documentController(), &KDevelop::IDocumentController::documentClosed, 0088 this, &Plugin::updateActions); 0089 connect(core()->documentController(), &KDevelop::IDocumentController::documentActivated, 0090 this, &Plugin::updateActions); 0091 0092 connect(core()->projectController(), &KDevelop::IProjectController::projectOpened, 0093 this, &Plugin::updateActions); 0094 connect(core()->projectController(), &KDevelop::IProjectController::projectClosed, 0095 this, &Plugin::projectClosed); 0096 0097 updateActions(); 0098 } 0099 0100 Plugin::~Plugin() 0101 { 0102 killVerapp(); 0103 } 0104 0105 bool Plugin::isRunning() 0106 { 0107 return m_job; 0108 } 0109 0110 void Plugin::killVerapp() 0111 { 0112 if (m_job) { 0113 m_job->kill(KJob::EmitResult); 0114 } 0115 } 0116 0117 void Plugin::raiseProblemsView() 0118 { 0119 m_model->show(); 0120 } 0121 0122 void Plugin::raiseOutputView() 0123 { 0124 core()->uiController()->findToolView( 0125 i18ndc("kdevstandardoutputview", "@title:window", "Test"), 0126 nullptr, 0127 KDevelop::IUiController::FindFlags::Raise); 0128 } 0129 0130 void Plugin::updateActions() 0131 { 0132 m_project = nullptr; 0133 0134 m_menuActionFile->setEnabled(false); 0135 m_menuActionProject->setEnabled(false); 0136 0137 if (isRunning()) { 0138 return; 0139 } 0140 0141 auto activeDocument = core()->documentController()->activeDocument(); 0142 if (!activeDocument) { 0143 return; 0144 } 0145 0146 m_project = core()->projectController()->findProjectForUrl(activeDocument->url()); 0147 if (!m_project) { 0148 return; 0149 } 0150 0151 m_menuActionFile->setEnabled(true); 0152 m_menuActionProject->setEnabled(true); 0153 } 0154 0155 void Plugin::projectClosed(KDevelop::IProject* project) 0156 { 0157 if (project != m_model->project()) { 0158 return; 0159 } 0160 0161 killVerapp(); 0162 m_model->reset(); 0163 } 0164 0165 void Plugin::runVerapp(bool checkProject) 0166 { 0167 auto doc = core()->documentController()->activeDocument(); 0168 Q_ASSERT(doc); 0169 0170 if (checkProject) { 0171 runVerapp(m_project, m_project->path().toUrl().toLocalFile()); 0172 } else { 0173 runVerapp(m_project, doc->url().toLocalFile()); 0174 } 0175 } 0176 0177 void Plugin::runVerapp(KDevelop::IProject* project, const QString& path) 0178 { 0179 Parameters params(project); 0180 params.checkPath = path; 0181 0182 m_model->reset(project, path); 0183 0184 if (!QFile::exists(params.executablePath)) { 0185 QString errorMessage; 0186 errorMessage += i18n("Failed to start vera++ from \"%1\".", params.executablePath); 0187 errorMessage += QStringLiteral("\n\n"); 0188 errorMessage += i18n("Check your settings and install the vera++ if necessary."); 0189 0190 KMessageBox::error(qApp->activeWindow(), errorMessage, i18n("Vera++ Error")); 0191 return; 0192 } 0193 0194 m_job = new Job(params); 0195 0196 connect(m_job, &Job::problemsDetected, m_model.data(), &ProblemModel::addProblems); 0197 connect(m_job, &Job::finished, this, &Plugin::result); 0198 0199 core()->uiController()->registerStatus(new KDevelop::JobStatus(m_job, "vera++")); 0200 core()->runController()->registerJob(m_job); 0201 0202 if (params.hideOutputView) { 0203 raiseProblemsView(); 0204 } else { 0205 raiseOutputView(); 0206 } 0207 0208 updateActions(); 0209 } 0210 0211 void Plugin::result(KJob*) 0212 { 0213 if (!core()->projectController()->projects().contains(m_model->project())) { 0214 m_model->reset(); 0215 } else { 0216 m_model->setProblems(); 0217 0218 if (m_job->status() == KDevelop::OutputExecuteJob::JobStatus::JobSucceeded || 0219 m_job->status() == KDevelop::OutputExecuteJob::JobStatus::JobCanceled) { 0220 0221 raiseProblemsView(); 0222 } else { 0223 raiseOutputView(); 0224 } 0225 } 0226 0227 m_job = nullptr; // job is automatically deleted later 0228 0229 updateActions(); 0230 } 0231 0232 KDevelop::ContextMenuExtension Plugin::contextMenuExtension(KDevelop::Context* context, QWidget* parent) 0233 { 0234 Q_UNUSED(parent); 0235 KDevelop::ContextMenuExtension extension; 0236 0237 if (context->hasType(KDevelop::Context::EditorContext) && m_project && !isRunning()) { 0238 auto eContext = static_cast<KDevelop::EditorContext*>(context); 0239 if (isSupportedUrl(eContext->url())) 0240 { 0241 extension.addAction(KDevelop::ContextMenuExtension::AnalyzeFileGroup, m_contextActionFile); 0242 } 0243 0244 extension.addAction(KDevelop::ContextMenuExtension::AnalyzeProjectGroup, m_contextActionProject); 0245 } 0246 0247 if (context->hasType(KDevelop::Context::ProjectItemContext) && !isRunning()) { 0248 auto pContext = dynamic_cast<KDevelop::ProjectItemContext*>(context); 0249 if (pContext->items().size() != 1) { 0250 return extension; 0251 } 0252 0253 auto item = pContext->items().first(); 0254 0255 switch (item->type()) { 0256 case KDevelop::ProjectBaseItem::File: { 0257 if (!isSupportedUrl(item->path().toUrl())) { 0258 return extension; 0259 } 0260 break; 0261 } 0262 case KDevelop::ProjectBaseItem::Folder: 0263 case KDevelop::ProjectBaseItem::BuildFolder: 0264 break; 0265 0266 default: 0267 return extension; 0268 } 0269 0270 m_contextActionProjectItem->disconnect(); 0271 connect(m_contextActionProjectItem, &QAction::triggered, [this, item](){ 0272 runVerapp(item->project(), item->path().toLocalFile()); 0273 }); 0274 0275 extension.addAction(KDevelop::ContextMenuExtension::AnalyzeProjectGroup, m_contextActionProjectItem); 0276 } 0277 0278 return extension; 0279 } 0280 0281 KDevelop::ConfigPage* Plugin::perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions& options, QWidget* parent) 0282 { 0283 if (number) { 0284 return nullptr; 0285 } 0286 0287 return new ProjectConfigPage(this, options.project, parent); 0288 } 0289 0290 KDevelop::ConfigPage* Plugin::configPage(int number, QWidget* parent) 0291 { 0292 if (number) { 0293 return nullptr; 0294 } 0295 0296 return new GlobalConfigPage(this, parent); 0297 } 0298 0299 } 0300 0301 #include "plugin.moc"