Commit 1ba4c4dd authored by Milian Wolff's avatar Milian Wolff
Browse files

Add a new problem scope: DocumentsInPath

This allows us to set a specific path filter which can be used to
reduces the size of the problem set. Note that this is similar
to the existing proxy model filter, but has the big advantage
that we can filter earlier. Especially for large projects, this
allows us to filter once, instead of repeatedly whenever you are
editing a file.
parent 64b4ce9d
......@@ -17,7 +17,8 @@ enum ProblemScope {
OpenDocuments,
CurrentProject,
AllProjects,
BypassScopeFilter // Special setting. Bypasses the filter in FilteredProblemStore
DocumentsInPath,
BypassScopeFilter // Special setting. Bypasses the filter in FilteredProblemStore
};
// How should problems be grouped
......
......@@ -390,6 +390,13 @@ void ProblemModel::setScope(ProblemScope scope)
d->m_problems->setScope(scope);
}
void ProblemModel::setPathForDocumentsInPathScope(const QString& path)
{
Q_D(ProblemModel);
d->m_problems->setPathForDocumentsInPathScope(path);
}
void ProblemModel::setSeverity(int severity)
{
switch (severity)
......
......@@ -167,6 +167,9 @@ public Q_SLOTS:
/// Sets the scope filter
void setScope(ProblemScope scope);
/// Sets the path filter for the DocumentsInPath scope
void setPathForDocumentsInPathScope(const QString& path);
/// Sets the severity filter
void setSeverity(int severity);///old-style severity filtering
......
......@@ -35,6 +35,9 @@ public:
/// Path of the currently open document
KDevelop::IndexedString m_currentDocument;
/// Path for the DocumentsInPath scope
QString m_pathForDocumentsInPathScope;
/// All stored problems
QVector<KDevelop::IProblem::Ptr> m_allProblems;
};
......@@ -222,6 +225,9 @@ void ProblemStore::setScope(ProblemScope scope)
case AllProjects:
d->m_documents = new AllProjectSet(this);
break;
case DocumentsInPath:
d->m_documents = new DocumentsInPathSet(d->m_pathForDocumentsInPathScope, this);
break;
case BypassScopeFilter:
d->m_documents = new BypassSet(this);
break;
......@@ -280,6 +286,23 @@ const KDevelop::IndexedString& ProblemStore::currentDocument() const
return d->m_currentDocument;
}
void ProblemStore::setPathForDocumentsInPathScope(const QString& path)
{
Q_D(ProblemStore);
d->m_pathForDocumentsInPathScope = path;
if (d->m_documents->scope() == DocumentsInPath) {
static_cast<DocumentsInPathSet*>(d->m_documents)->setPath(path);
}
}
QString ProblemStore::pathForDocumentsInPathScope() const
{
Q_D(const ProblemStore);
return d->m_pathForDocumentsInPathScope;
}
void ProblemStore::onDocumentSetChanged()
{
......
......@@ -117,6 +117,12 @@ public:
/// Retrieves the path of the current document
const KDevelop::IndexedString& currentDocument() const;
/// Sets the path to a folder to be used by the ProblemScope::DocumentsInPath scope
void setPathForDocumentsInPathScope(const QString& path);
/// Retrieves the path to the folder to be used by the ProblemScope::DocumentsInPath scope
QString pathForDocumentsInPathScope() const;
Q_SIGNALS:
/// Emitted when any store setting (grouping, scope, severity, document) is changed
void changed();
......
......@@ -117,6 +117,13 @@ public:
getImportsFromDUChain();
}
void clear()
{
m_documents.clear();
m_imports.clear();
emit m_documentSet->changed();
}
private:
void getImportsFromDU(TopDUContext* context, QSet<TopDUContext*>& visitedContexts)
{
......@@ -275,7 +282,10 @@ void ProjectSet::fileAdded(ProjectFileItem* file)
{
Q_D(WatchedDocumentSet);
d->addDocument(IndexedString(file->indexedPath()), DoUpdate | DoEmit);
const auto path = IndexedString(file->indexedPath());
if (include(path)) {
d->addDocument(path, DoUpdate | DoEmit);
}
}
void ProjectSet::fileRemoved(ProjectFileItem* file)
......@@ -290,7 +300,7 @@ void ProjectSet::fileRenamed(const Path& oldFile, ProjectFileItem* newFile)
Q_D(WatchedDocumentSet);
d->delDocument(IndexedString(oldFile.pathOrUrl()));
d->addDocument(IndexedString(newFile->indexedPath()), DoUpdate | DoEmit);
fileAdded(newFile);
}
void ProjectSet::trackProjectFiles(const IProject* project)
......@@ -341,19 +351,43 @@ ProblemScope CurrentProjectSet::scope() const
}
AllProjectSet::AllProjectSet(QObject* parent)
: AllProjectSet(InitFlag::LoadOnInit, parent)
{
}
AllProjectSet::AllProjectSet(InitFlag initFlag, QObject* parent)
: ProjectSet(parent)
{
switch (initFlag) {
case InitFlag::LoadOnInit:
reload();
break;
case InitFlag::SkipLoadOnInit:
break;
}
}
void AllProjectSet::reload()
{
Q_D(WatchedDocumentSet);
d->clear();
const auto projects = ICore::self()->projectController()->projects();
for (const IProject* project : projects) {
const auto fileSet = project->fileSet();
for (const IndexedString& indexedString : fileSet) {
d->addDocument(indexedString);
if (include(indexedString)) {
d->addDocument(indexedString);
}
}
const auto projectPath = IndexedString(project->path().toLocalFile());
if (include(projectPath)) {
d->addDocument(projectPath);
}
d->addDocument(IndexedString(project->path().toLocalFile()));
trackProjectFiles(project);
}
d->updateImports();
emit changed();
}
......@@ -363,6 +397,37 @@ ProblemScope AllProjectSet::scope() const
return AllProjects;
}
DocumentsInPathSet::DocumentsInPathSet(const QString& path, QObject* parent)
: AllProjectSet(InitFlag::SkipLoadOnInit, parent)
, m_path(path)
{
reload();
}
ProblemScope DocumentsInPathSet::scope() const
{
return DocumentsInPath;
}
void DocumentsInPathSet::setPath(const QString& path)
{
if (m_path == path) {
return;
}
m_path = path;
reload();
}
bool DocumentsInPathSet::include(const IndexedString& path) const
{
if (m_path.isEmpty()) {
return true;
}
return path.str().contains(m_path, Qt::CaseInsensitive);
}
BypassSet::BypassSet(QObject* parent)
: WatchedDocumentSet(parent)
{
......
......@@ -96,6 +96,9 @@ protected Q_SLOTS:
void fileAdded(ProjectFileItem*);
void fileRemoved(ProjectFileItem* file);
void fileRenamed(const Path& oldFile, ProjectFileItem* newFile);
protected:
virtual bool include(const IndexedString& /*url*/) const { return true; }
};
/**
......@@ -120,6 +123,28 @@ class AllProjectSet : public ProjectSet
public:
explicit AllProjectSet(QObject* parent);
ProblemScope scope() const override;
protected:
enum class InitFlag {
LoadOnInit,
SkipLoadOnInit,
};
explicit AllProjectSet(InitFlag initFlag, QObject* parent);
void reload();
};
class DocumentsInPathSet : public AllProjectSet
{
Q_OBJECT
public:
explicit DocumentsInPathSet(const QString& path, QObject* parent);
ProblemScope scope() const override;
void setPath(const QString& path);
private:
bool include(const IndexedString& url) const override;
QString m_path;
};
class BypassSet : public WatchedDocumentSet
......
......@@ -69,16 +69,17 @@ void ProblemsView::setupActions()
allProjectAction->setText(i18nc("@option:check", "All Projects"));
allProjectAction->setToolTip(i18nc("@info:tooltip", "Display problems in all projects"));
auto* documentsInPathAction = new QAction(this);
documentsInPathAction->setText(i18nc("@option:check", "Documents In Path"));
documentsInPathAction->setToolTip(i18nc("@info:tooltip", "Display problems from all files in a specific path"));
m_showAllAction = new QAction(this);
m_showAllAction->setText(i18nc("@option:check", "Show All"));
m_showAllAction->setToolTip(i18nc("@info:tooltip", "Display all problems"));
QAction* const actions[] = {
m_currentDocumentAction,
openDocumentsAction,
currentProjectAction,
allProjectAction,
m_showAllAction,
m_currentDocumentAction, openDocumentsAction, currentProjectAction,
allProjectAction, documentsInPathAction, m_showAllAction,
};
for (QAction* action : actions) {
......@@ -88,10 +89,35 @@ void ProblemsView::setupActions()
}
addAction(m_scopeMenu);
{
auto* updatePathTimer = new QTimer(this);
updatePathTimer->setSingleShot(true);
updatePathTimer->setInterval(500);
auto* pathEdit = new KExpandableLineEdit(this);
pathEdit->setClearButtonEnabled(true);
pathEdit->setPlaceholderText(i18nc("@info:placeholder", "Path Filter..."));
connect(updatePathTimer, &QTimer::timeout, this,
[this, pathEdit]() { currentView()->model()->setPathForDocumentsInPathScope(pathEdit->text()); });
connect(pathEdit, &QLineEdit::textChanged, updatePathTimer,
static_cast<void (QTimer::*)()>(&QTimer::start));
auto* pathForForDocumentsInPathAction = new QWidgetAction(this);
pathForForDocumentsInPathAction->setDefaultWidget(pathEdit);
addAction(pathForForDocumentsInPathAction);
connect(documentsInPathAction, &QAction::toggled, pathForForDocumentsInPathAction, &QAction::setVisible);
pathForForDocumentsInPathAction->setVisible(false);
}
connect(m_currentDocumentAction, &QAction::triggered, this, [this](){ setScope(CurrentDocument); });
connect(openDocumentsAction, &QAction::triggered, this, [this](){ setScope(OpenDocuments); });
connect(currentProjectAction, &QAction::triggered, this, [this](){ setScope(CurrentProject); });
connect(allProjectAction, &QAction::triggered, this, [this](){ setScope(AllProjects); });
connect(documentsInPathAction, &QAction::triggered, this, [this]() { setScope(DocumentsInPath); });
connect(m_showAllAction, &QAction::triggered, this, [this](){ setScope(BypassScopeFilter); });
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment