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