File indexing completed on 2024-04-28 08:25:29
0001 /* 0002 * This file is part of KDevelop Krazy2 Plugin. 0003 * 0004 * Copyright 2012 Daniel Calviño Sánchez <danxuliu@gmail.com> 0005 * 0006 * This program is free software; you can redistribute it and/or 0007 * modify it under the terms of the GNU General Public License 0008 * as published by the Free Software Foundation; either version 2 0009 * of the License, or (at your option) any later version. 0010 * 0011 * This program is distributed in the hope that it will be useful, 0012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0014 * GNU General Public License for more details. 0015 * 0016 * You should have received a copy of the GNU General Public License 0017 * along with this program. If not, see <http://www.gnu.org/licenses/>. 0018 */ 0019 0020 #include "krazy2plugin.h" 0021 0022 #include <KAboutData> 0023 #include <KLocalizedString> 0024 #include <KPluginFactory> 0025 #include <KActionCollection> 0026 0027 #include <interfaces/icore.h> 0028 #include <interfaces/iuicontroller.h> 0029 #include <interfaces/ilanguagecontroller.h> 0030 0031 #include <interfaces/iruncontroller.h> 0032 #include <interfaces/idocumentcontroller.h> 0033 #include <interfaces/idocument.h> 0034 #include <interfaces/iprojectcontroller.h> 0035 #include <interfaces/iproject.h> 0036 0037 #include <language/editor/documentrange.h> 0038 0039 #include "./settings/krazy2preferences.h" 0040 #include "./settings/krazy2projectsettings.h" 0041 0042 #include <QAction> 0043 0044 #include <KLocalizedString> 0045 0046 #include <kdevplatform/project/projectconfigpage.h> 0047 #include <shell/problemmodelset.h> 0048 #include <shell/problemmodel.h> 0049 #include <shell/problem.h> 0050 0051 #include "./checker.h" 0052 #include "./checkerlistjob.h" 0053 #include "./analysisparameters.h" 0054 #include "./analysisjob.h" 0055 #include "./analysisresults.h" 0056 #include "./issue.h" 0057 0058 #include <QMessageBox> 0059 0060 //KPluginFactory stuff to load the plugin dynamically at runtime 0061 K_PLUGIN_FACTORY_WITH_JSON(KDevKrazy2Factory, "kdevkrazy2.json", registerPlugin<Krazy2Plugin>();) 0062 0063 //public: 0064 0065 Krazy2Plugin::Krazy2Plugin(QObject* parent, const QVariantList& /*= QVariantList()*/): 0066 KDevelop::IPlugin("kdevkrazy2", parent), 0067 m_analysisInProgress(false), 0068 m_model(new KDevelop::ProblemModel(parent)), 0069 m_results(nullptr){ 0070 setXMLFile("kdevkrazy2.rc"); 0071 0072 grabCheckerList(); 0073 0074 auto checkFileAction = new QAction(this); 0075 checkFileAction->setText(i18n("Krazy2 check (selected files)")); 0076 checkFileAction->setStatusTip(i18n("Check selected files with Krazy2 tools")); 0077 connect(checkFileAction, &QAction::triggered, this, &Krazy2Plugin::checkSelectedFiles); 0078 0079 auto checkAllFilesAction = new QAction(this); 0080 checkAllFilesAction->setText(i18n("Krazy2 check (all files)")); 0081 checkAllFilesAction->setStatusTip(i18n("Check all files with Krazy2 tools")); 0082 connect(checkAllFilesAction, &QAction::triggered, this, &Krazy2Plugin::checkAllFiles); 0083 0084 actionCollection()->addAction("krazy2_selected", checkFileAction); 0085 actionCollection()->addAction("krazy2_all", checkAllFilesAction); 0086 0087 KDevelop::ProblemModelSet *set = KDevelop::ICore::self()->languageController()->problemModelSet(); 0088 set->addModel(QStringLiteral("Krazy2"), i18n("Krazy2"), m_model); 0089 } 0090 0091 Krazy2Plugin::~Krazy2Plugin() { 0092 } 0093 0094 void Krazy2Plugin::unload() { 0095 KDevelop::ProblemModelSet *set = KDevelop::ICore::self()->languageController()->problemModelSet(); 0096 set->removeModel(QStringLiteral("Krazy2")); 0097 } 0098 0099 KDevelop::ConfigPage* Krazy2Plugin::configPage(int number, QWidget *parent) 0100 { 0101 if (number != 0) 0102 return nullptr; 0103 0104 return new Krazy2Preferences(this, parent); 0105 } 0106 0107 KDevelop::ConfigPage* Krazy2Plugin::perProjectConfigPage(int number, const KDevelop::ProjectConfigOptions &options, QWidget *parent) 0108 { 0109 if (number != 0) 0110 return nullptr; 0111 0112 return new Krazy2ProjectSettings(options.project, &m_checkers, parent); 0113 } 0114 0115 void Krazy2Plugin::checkSelectedFiles() 0116 { 0117 check(false); 0118 } 0119 0120 void Krazy2Plugin::checkAllFiles() 0121 { 0122 check(true); 0123 } 0124 0125 void Krazy2Plugin::onListingFinished(KJob *job) 0126 { 0127 if (job->error() != KJob::NoError) { 0128 QMessageBox::critical(nullptr, 0129 i18n("Error gathering checker list"), 0130 i18n("There was an error while gathering the checker list")); 0131 return; 0132 } 0133 } 0134 0135 void Krazy2Plugin::onAnalysisFinished(KJob *job) 0136 { 0137 m_analysisInProgress = false; 0138 0139 if (job->error() != KJob::NoError) { 0140 QMessageBox::critical(nullptr, 0141 i18n("Error running Krazy2"), 0142 i18n("There was an error with the Krazy2 process")); 0143 return; 0144 } 0145 0146 // Retrieve list of found issues 0147 const QList<const Issue*> issues = m_results->issues(); 0148 QVector<KDevelop::IProblem::Ptr> problems; 0149 0150 // Build a Problem objects from these issues 0151 foreach (const Issue* issue, issues) { 0152 KDevelop::DocumentRange range; 0153 range.document = KDevelop::IndexedString(issue->fileName()); 0154 range.setBothLines(issue->line()); 0155 0156 KDevelop::IProblem::Ptr problem(new KDevelop::DetectedProblem()); 0157 if(!issue->message().isEmpty()) 0158 problem->setDescription(issue->message()); 0159 else 0160 problem->setDescription(issue->checker()->description()); 0161 0162 if(problem->description().isEmpty()) 0163 problem->setDescription(i18n("The tool didn't provide a message.")); 0164 0165 problem->setFinalLocation(range); 0166 problem->setSource(KDevelop::IProblem::Plugin); 0167 problem->setSeverity(KDevelop::IProblem::Warning); 0168 0169 problems.push_back(problem); 0170 } 0171 0172 m_model->setProblems(problems); 0173 } 0174 0175 void Krazy2Plugin::grabCheckerList() 0176 { 0177 auto job = new CheckerListJob(this); 0178 job->setCheckerList(&m_checkers); 0179 0180 connect(job, &KJob::finished, this, &Krazy2Plugin::onListingFinished); 0181 0182 core()->runController()->registerJob(job); 0183 } 0184 0185 void Krazy2Plugin::check(bool allFiles) 0186 { 0187 if (m_analysisInProgress) { 0188 QMessageBox::critical(nullptr, 0189 i18n("Error starting Krazy2"), 0190 i18n("Analysis already in progress")); 0191 return; 0192 } 0193 0194 if (m_checkers.isEmpty()) { 0195 QMessageBox::critical(nullptr, 0196 i18n("Error starting Krazy2"), 0197 i18n("Gathering the checkers list hasn't finished yet or has failed.")); 0198 return; 0199 } 0200 0201 KDevelop::IDocument *doc = KDevelop::ICore::self()->documentController()->activeDocument(); 0202 if (!doc) { 0203 QMessageBox::critical(nullptr, 0204 i18n("Error starting Krazy2"), 0205 i18n("No file is active, cannot deduce project.")); 0206 return; 0207 } 0208 0209 KDevelop::IProject *proj = KDevelop::ICore::self()->projectController()->findProjectForUrl(doc->url()); 0210 if (!proj) { 0211 QMessageBox::critical(nullptr, 0212 i18n("Error starting Krazy2"), 0213 i18n("Cannot find project")); 0214 return; 0215 } 0216 0217 KSharedConfigPtr ptr = proj->projectConfiguration(); 0218 KConfigGroup group = ptr->group("Krazy2"); 0219 if (!group.isValid()) { 0220 QMessageBox::critical(nullptr, 0221 i18n("Error starting Krazy2"), 0222 i18n("Krazy2 settings need to be set in the project settings")); 0223 return; 0224 } 0225 0226 if (!group.hasKey("SelectedCheckers")) { 0227 QMessageBox::critical(nullptr, 0228 i18n("Error starting Krazy2"), 0229 i18n("No checkers selected")); 0230 return; 0231 } 0232 0233 QStringList paths; 0234 0235 if (!allFiles) { 0236 if (!group.hasKey("SelectedPaths")) { 0237 QMessageBox::critical(nullptr, 0238 i18n("Error starting Krazy2"), 0239 i18n("No paths selected")); 0240 return; 0241 } 0242 0243 paths = group.readEntry("SelectedPaths",QStringList()); 0244 if(paths.isEmpty()) { 0245 QMessageBox::critical(nullptr, 0246 i18n("Error starting Krazy2"), 0247 i18n("No paths selected")); 0248 return; 0249 } 0250 } 0251 else { 0252 paths.push_back(proj->path().toUrl().toLocalFile()); 0253 } 0254 0255 QStringList csl = group.readEntry("SelectedCheckers", QStringList()); 0256 if (csl.isEmpty()) { 0257 QMessageBox::critical(nullptr, 0258 i18n("Error starting Krazy2"), 0259 i18n("No checkers selected")); 0260 return; 0261 } 0262 0263 QList<const Checker*> cl; 0264 0265 // Build the checkers list from the saves checker filetypes and names 0266 foreach (const QString &s, csl) { 0267 const Checker *c = findChecker(m_checkers, s); 0268 if(c) 0269 cl.push_back(c); 0270 } 0271 0272 if (cl.isEmpty()) { 0273 QMessageBox::critical(nullptr, 0274 i18n("Error starting Krazy2"), 0275 i18n("Unable to restore selected checkers")); 0276 return; 0277 } 0278 0279 check(paths, cl); 0280 } 0281 0282 void Krazy2Plugin::check(QStringList paths, QList<const Checker *> &selectedCheckers) 0283 { 0284 auto params = new AnalysisParameters(); 0285 params->initializeCheckers(m_checkers); 0286 params->setCheckersToRun(selectedCheckers); 0287 params->setFilesAndDirectories(paths); 0288 0289 m_results.reset(new AnalysisResults()); 0290 0291 auto job = new AnalysisJob(this); 0292 job->addAnalysisParameters(params); 0293 job->setAnalysisResults(m_results.data()); 0294 0295 connect(job, &KJob::finished, this, &Krazy2Plugin::onAnalysisFinished); 0296 0297 KDevelop::ICore::self()->runController()->registerJob(job); 0298 m_analysisInProgress = true; 0299 } 0300 0301 0302 0303 #include "krazy2plugin.moc"