diff --git a/kdevplatform/interfaces/iprojectcontroller.h b/kdevplatform/interfaces/iprojectcontroller.h --- a/kdevplatform/interfaces/iprojectcontroller.h +++ b/kdevplatform/interfaces/iprojectcontroller.h @@ -148,8 +148,12 @@ virtual void configureProject( IProject* ) = 0; - /// Schedules all files of the @p project for reparsing by @see BackgroundParser - virtual void reparseProject( IProject* project, bool ForceUpdate = false ) = 0; + /** + * Schedules all files of the @p project for reparsing by @see BackgroundParser + * The @p forceAll argument is for triggering a full reparse of the entire project + * after the initial import. + */ + virtual void reparseProject( IProject* project, bool forceUpdate = false, bool forceAll = false ) = 0; // virtual void changeCurrentProject( KDevelop::ProjectBaseItem* ) = 0; diff --git a/kdevplatform/language/backgroundparser/parseprojectjob.h b/kdevplatform/language/backgroundparser/parseprojectjob.h --- a/kdevplatform/language/backgroundparser/parseprojectjob.h +++ b/kdevplatform/language/backgroundparser/parseprojectjob.h @@ -28,15 +28,21 @@ 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; diff --git a/kdevplatform/language/backgroundparser/parseprojectjob.cpp b/kdevplatform/language/backgroundparser/parseprojectjob.cpp --- a/kdevplatform/language/backgroundparser/parseprojectjob.cpp +++ b/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; }; @@ -68,21 +70,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); @@ -160,7 +162,7 @@ } } - if (!ICore::self()->projectController()->parseAllProjectSources()) { + if (!d->forceAll && !ICore::self()->projectController()->parseAllProjectSources()) { return; } diff --git a/kdevplatform/shell/projectcontroller.h b/kdevplatform/shell/projectcontroller.h --- a/kdevplatform/shell/projectcontroller.h +++ b/kdevplatform/shell/projectcontroller.h @@ -113,7 +113,7 @@ void closeAllProjects() override; void configureProject( IProject* ) override; - void reparseProject( IProject* project, bool forceUpdate = false ) override; + void reparseProject( IProject* project, bool forceUpdate = false, bool forceAll = false ) override; void eventuallyOpenProjectFile(KIO::Job* job, const KIO::UDSEntryList& entries); void openProjectForUrlSlot(bool); diff --git a/kdevplatform/shell/projectcontroller.cpp b/kdevplatform/shell/projectcontroller.cpp --- a/kdevplatform/shell/projectcontroller.cpp +++ b/kdevplatform/shell/projectcontroller.cpp @@ -263,42 +263,37 @@ 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) { - auto* 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; // if only one project loaded, this is our target if (m_projects.count() == 1) { projects.insert(m_projects.at(0)); } else { // otherwise base on selection - auto* ctx = dynamic_cast(ICore::self()->selectionController()->currentSelection()); + auto* ctx = dynamic_cast(ICore::self()->selectionController()->currentSelection()); if (ctx) { foreach (ProjectBaseItem* item, ctx->items()) { projects.insert(item->project()); } } } + 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,26 @@ { 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() ) { + + auto* action = new QAction(i18n("Reparse the Entire Project"), this); + connect(action, &QAction::triggered, this, [&] { + foreach (auto project, d->selectedProjects()) { + reparseProject(project, true, true); + } + }); + + 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; } @@ -1285,13 +1294,13 @@ return QString(); } -void ProjectController::reparseProject( IProject* project, bool forceUpdate ) -{ + void KDevelop::ProjectController::reparseProject(IProject *project, bool forceUpdate, bool forceAll) + { if (auto job = d->m_parseJobs.value(project)) { job->kill(); } - d->m_parseJobs[project] = new KDevelop::ParseProjectJob(project, forceUpdate); + d->m_parseJobs[project] = new KDevelop::ParseProjectJob(project, forceUpdate, forceAll); ICore::self()->runController()->registerJob(d->m_parseJobs[project]); }