Index: kdevplatform/language/backgroundparser/parseprojectjob.h =================================================================== --- kdevplatform/language/backgroundparser/parseprojectjob.h +++ kdevplatform/language/backgroundparser/parseprojectjob.h @@ -28,13 +28,19 @@ class ReferencedTopDUContext; class IProject; -///A job that parses all project-files in the given project -///Deletes itself as soon as the project is deleted +///A job that parses all project-files in the given project either +///when KDevelop is configured to parse all files at project import +///(see ProjectController:parseAllProjectSources()) or when the +///forceAll argument is true. That forceAll argument allows to +///trigger a full project reparse after the initial import, e.g. +///via the project manager's context menu. +///ParseProjectJob instances delete themselves as soon as the project +///is deleted or when a new job is started. class KDEVPLATFORMLANGUAGE_EXPORT ParseProjectJob : public KJob { Q_OBJECT public: - explicit ParseProjectJob(KDevelop::IProject* project, bool forceUpdate = false ); + explicit ParseProjectJob(KDevelop::IProject* project, bool forceUpdate = false, bool forceAll = false ); ~ParseProjectJob() override; void start() override; bool doKill() override; Index: kdevplatform/language/backgroundparser/parseprojectjob.cpp =================================================================== --- kdevplatform/language/backgroundparser/parseprojectjob.cpp +++ kdevplatform/language/backgroundparser/parseprojectjob.cpp @@ -41,14 +41,16 @@ class KDevelop::ParseProjectJobPrivate { public: - ParseProjectJobPrivate(IProject* project, bool forceUpdate) + ParseProjectJobPrivate(IProject* project, bool forceUpdate, bool forceAll) : forceUpdate(forceUpdate) + , forceAll(forceAll) , project(project) { } int updated = 0; bool forceUpdate; + bool forceAll; KDevelop::IProject* project; QSet filesToParse; }; @@ -66,21 +68,21 @@ ICore::self()->runController()->unregisterJob(this); } -ParseProjectJob::ParseProjectJob(IProject* project, bool forceUpdate) - : d(new ParseProjectJobPrivate(project, forceUpdate)) +ParseProjectJob::ParseProjectJob(IProject* project, bool forceUpdate, bool forceAll) + : d(new ParseProjectJobPrivate(project, forceUpdate, forceAll)) { connect(project, &IProject::destroyed, this, &ParseProjectJob::deleteNow); - if (!ICore::self()->projectController()->parseAllProjectSources()) { + if (forceAll || ICore::self()->projectController()->parseAllProjectSources()) { + d->filesToParse = project->fileSet(); + } else { // In case we don't want to parse the whole project, still add all currently open files that belong to the project to the background-parser foreach (auto document, ICore::self()->documentController()->openDocuments()) { const auto path = IndexedString(document->url()); if (project->fileSet().contains(path)) { d->filesToParse.insert(path); } } - } else { - d->filesToParse = project->fileSet(); } setCapabilities(Killable); @@ -147,7 +149,7 @@ } } - if (!ICore::self()->projectController()->parseAllProjectSources()) { + if (!d->forceAll && !ICore::self()->projectController()->parseAllProjectSources()) { return; } Index: kdevplatform/shell/projectcontroller.cpp =================================================================== --- kdevplatform/shell/projectcontroller.cpp +++ kdevplatform/shell/projectcontroller.cpp @@ -263,25 +263,7 @@ m_closeProject->setEnabled(itemCount > 0); } - void openProjectConfig() - { - // if only one project loaded, this is our target - IProject *project = (m_projects.count() == 1) ? m_projects.at(0) : nullptr; - - // otherwise base on selection - if (!project) { - ProjectItemContext* ctx = dynamic_cast(ICore::self()->selectionController()->currentSelection()); - if (ctx && ctx->items().count() == 1) { - project = ctx->items().at(0)->project(); - } - } - - if (project) { - q->configureProject(project); - } - } - - void closeSelectedProjects() + QSet selectedProjects() { QSet projects; @@ -297,8 +279,21 @@ } } } + return projects; + } + + void openProjectConfig() + { + auto projects = selectedProjects(); + + if (projects.count() == 1) { + q->configureProject(*projects.constBegin()); + } + } - foreach (IProject* project, projects) { + void closeSelectedProjects() + { + foreach (IProject* project, selectedProjects()) { q->closeProject(project); } } @@ -1180,12 +1175,32 @@ { Q_UNUSED(parent); ContextMenuExtension ext; - if ( ctx->type() != Context::ProjectItemContext || !static_cast(ctx)->items().isEmpty() ) { + if ( ctx->type() != Context::ProjectItemContext) { + return ext; + } + if (!static_cast(ctx)->items().isEmpty() ) { + + QAction *action = new QAction(this); + connect(action, &QAction::triggered, this, [&] { + foreach (auto project, d->selectedProjects()) { + // can't use reparseProject() here because we need the forceAll argument + if (auto job = d->m_parseJobs.value(project)) { + job->kill(); + } + d->m_parseJobs[project] = new KDevelop::ParseProjectJob(project, true, true); + ICore::self()->runController()->registerJob(d->m_parseJobs[project]); + } + }); + + action->setText( i18n( "Reparse the Entire Project" ) ); + ext.addAction(ContextMenuExtension::ProjectGroup, action); return ext; } + ext.addAction(ContextMenuExtension::ProjectGroup, d->m_openProject); ext.addAction(ContextMenuExtension::ProjectGroup, d->m_fetchProject); ext.addAction(ContextMenuExtension::ProjectGroup, d->m_recentProjectsAction); + return ext; }