1 /*
2 SPDX-FileCopyrightText: 2013 Milian Wolff <mail@milianw.de>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5 */
6
7 #include "projectfiltermanager.h"
8
9 #include <QVector>
10
11 #include <interfaces/iproject.h>
12 #include <interfaces/iplugin.h>
13 #include <interfaces/icore.h>
14 #include <interfaces/iplugincontroller.h>
15
16 #include "interfaces/iprojectfilterprovider.h"
17 #include "interfaces/iprojectfilter.h"
18 #include "interfaces/iprojectfilemanager.h"
19 #include "debug.h"
20
21 using namespace KDevelop;
22
23 //BEGIN helper
24 namespace {
25
26 struct Filter
27 {
28 QSharedPointer<IProjectFilter> filter;
29 // required for bookkeeping
30 IProjectFilterProvider* provider;
31 };
32
33 }
34
35 Q_DECLARE_TYPEINFO(Filter, Q_MOVABLE_TYPE);
36
37 //END helper
38
39 //BEGIN private
40 class KDevelop::ProjectFilterManagerPrivate
41 {
42 public:
43 void pluginLoaded(IPlugin* plugin);
44 void unloadingPlugin(IPlugin* plugin);
45 void filterChanged(IProjectFilterProvider* provider, IProject* project);
46
47 QVector<IProjectFilterProvider*> m_filterProvider;
48 QHash<IProject*, QVector<Filter> > m_filters;
49
50 ProjectFilterManager* q;
51 };
52
pluginLoaded(IPlugin * plugin)53 void ProjectFilterManagerPrivate::pluginLoaded(IPlugin* plugin)
54 {
55 auto* filterProvider = plugin->extension<IProjectFilterProvider>();
56 if (filterProvider) {
57 m_filterProvider << filterProvider;
58 // can't use qt5 signal slot syntax here, IProjectFilterProvider is not a QObject
59 QObject::connect(plugin, SIGNAL(filterChanged(KDevelop::IProjectFilterProvider*,KDevelop::IProject*)),
60 q, SLOT(filterChanged(KDevelop::IProjectFilterProvider*,KDevelop::IProject*)));
61 QHash< IProject*, QVector< Filter > >::iterator it = m_filters.begin();
62 while(it != m_filters.end()) {
63 Filter filter;
64 filter.provider = filterProvider;
65 filter.filter = filterProvider->createFilter(it.key());
66 it.value().append(filter);
67 ++it;
68 }
69 }
70 }
71
unloadingPlugin(IPlugin * plugin)72 void ProjectFilterManagerPrivate::unloadingPlugin(IPlugin* plugin)
73 {
74 auto* filterProvider = plugin->extension<IProjectFilterProvider>();
75 if (filterProvider) {
76 int idx = m_filterProvider.indexOf(qobject_cast<IProjectFilterProvider*>(plugin));
77 Q_ASSERT(idx != -1);
78 m_filterProvider.remove(idx);
79 QHash< IProject*, QVector<Filter> >::iterator filtersIt = m_filters.begin();
80 while(filtersIt != m_filters.end()) {
81 QVector<Filter>& filters = filtersIt.value();
82 QVector<Filter>::iterator filter = filters.begin();
83 while(filter != filters.end()) {
84 if ((*filter).provider == filterProvider) {
85 filter = filters.erase(filter);
86 continue;
87 }
88 ++filter;
89 }
90 ++filtersIt;
91 }
92 }
93 }
94
filterChanged(IProjectFilterProvider * provider,IProject * project)95 void ProjectFilterManagerPrivate::filterChanged(IProjectFilterProvider* provider, IProject* project)
96 {
97 if (!m_filters.contains(project)) {
98 return;
99 }
100
101 QVector< Filter >& filters = m_filters[project];
102 for (auto& filter : filters) {
103 if (filter.provider == provider) {
104 filter.filter = provider->createFilter(project);
105 qCDebug(PROJECT) << "project filter changed, reloading" << project->name();
106 project->projectFileManager()->reload(project->projectItem());
107 return;
108 }
109 }
110 Q_ASSERT_X(false, Q_FUNC_INFO, "Unknown provider changed its filter");
111 }
112 //END private
113
114 //BEGIN
ProjectFilterManager(QObject * parent)115 ProjectFilterManager::ProjectFilterManager(QObject* parent)
116 : QObject(parent)
117 , d_ptr(new ProjectFilterManagerPrivate)
118 {
119 Q_D(ProjectFilterManager);
120
121 d->q = this;
122
123 connect(ICore::self()->pluginController(), &IPluginController::pluginLoaded,
124 this, [this] (IPlugin* plugin) { Q_D(ProjectFilterManager);d->pluginLoaded(plugin); });
125 connect(ICore::self()->pluginController(), &IPluginController::unloadingPlugin,
126 this, [this] (IPlugin* plugin) { Q_D(ProjectFilterManager);d->unloadingPlugin(plugin); });
127
128 const auto plugins = ICore::self()->pluginController()->loadedPlugins();
129 for (IPlugin* plugin : plugins) {
130 d->pluginLoaded(plugin);
131 }
132 }
133
~ProjectFilterManager()134 ProjectFilterManager::~ProjectFilterManager()
135 {
136
137 }
138
add(IProject * project)139 void ProjectFilterManager::add(IProject* project)
140 {
141 Q_D(ProjectFilterManager);
142
143 QVector<Filter> filters;
144 filters.reserve(d->m_filterProvider.size());
145 for (IProjectFilterProvider* provider : qAsConst(d->m_filterProvider)) {
146 Filter filter;
147 filter.provider = provider;
148 filter.filter = provider->createFilter(project);
149 filters << filter;
150 }
151 d->m_filters[project] = filters;
152 }
153
remove(IProject * project)154 void ProjectFilterManager::remove(IProject* project)
155 {
156 Q_D(ProjectFilterManager);
157
158 d->m_filters.remove(project);
159 }
160
isManaged(IProject * project) const161 bool ProjectFilterManager::isManaged(IProject* project) const
162 {
163 Q_D(const ProjectFilterManager);
164
165 return d->m_filters.contains(project);
166 }
167
isValid(const Path & path,bool isFolder,IProject * project) const168 bool ProjectFilterManager::isValid(const Path& path, bool isFolder, IProject* project) const
169 {
170 Q_D(const ProjectFilterManager);
171
172 const auto filters = d->m_filters[project];
173 return std::all_of(filters.begin(), filters.end(), [&](const Filter& filter) {
174 return (filter.filter->isValid(path, isFolder));
175 });
176 }
177
filtersForProject(IProject * project) const178 QVector< QSharedPointer< IProjectFilter > > ProjectFilterManager::filtersForProject(IProject* project) const
179 {
180 Q_D(const ProjectFilterManager);
181
182 QVector< QSharedPointer< IProjectFilter > > ret;
183 const QVector<Filter>& filters = d->m_filters[project];
184 ret.reserve(filters.size());
185 for (const Filter& filter : filters) {
186 ret << filter.filter;
187 }
188 return ret;
189 }
190 //END
191
192 #include "moc_projectfiltermanager.cpp"
193