File indexing completed on 2024-04-28 04:39:08

0001 /*
0002     SPDX-FileCopyrightText: 2013 Milian Wolff <mail@milianw.de>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "projectfilterprovider.h"
0008 
0009 #include <KPluginFactory>
0010 #include <KMessageBox>
0011 #include <KParts/MainWindow>
0012 #include <KLocalizedString>
0013 
0014 #include <QAction>
0015 #include <QIcon>
0016 
0017 #include <interfaces/iproject.h>
0018 #include <interfaces/icore.h>
0019 #include <interfaces/iprojectcontroller.h>
0020 #include <interfaces/context.h>
0021 #include <interfaces/contextmenuextension.h>
0022 #include <interfaces/iuicontroller.h>
0023 
0024 #include <debug.h>
0025 #include "projectfilterconfigpage.h"
0026 #include <project/projectmodel.h>
0027 
0028 using namespace KDevelop;
0029 
0030 K_PLUGIN_FACTORY_WITH_JSON(ProjectFilterProviderFactory, "kdevprojectfilter.json", registerPlugin<ProjectFilterProvider>();)
0031 
0032 ProjectFilterProvider::ProjectFilterProvider( QObject* parent, const QVariantList& /*args*/ )
0033     : IPlugin( QStringLiteral( "kdevprojectfilter" ), parent )
0034 {
0035     connect(core()->projectController(), &IProjectController::projectClosing,
0036             this, &ProjectFilterProvider::projectClosing);
0037     connect(core()->projectController(), &IProjectController::projectAboutToBeOpened,
0038             this, &ProjectFilterProvider::projectAboutToBeOpened);
0039 
0040     // initialize the filters for each project
0041     const auto projects = core()->projectController()->projects();
0042     for (IProject* project : projects) {
0043         updateProjectFilters(project);
0044     }
0045 }
0046 
0047 QSharedPointer<IProjectFilter> ProjectFilterProvider::createFilter(IProject* project) const
0048 {
0049     return QSharedPointer<IProjectFilter>(new ProjectFilter(project, m_filters[project]));
0050 }
0051 
0052 ContextMenuExtension ProjectFilterProvider::contextMenuExtension(Context* context, QWidget* parent)
0053 {
0054     ContextMenuExtension ret;
0055     if (!context->hasType(Context::ProjectItemContext)) {
0056         return ret;
0057     }
0058 
0059     auto* ctx = static_cast<ProjectItemContext*>( context );
0060 
0061     QList<ProjectBaseItem*> items = ctx->items();
0062     // filter out project roots and items in targets
0063     QList< ProjectBaseItem* >::iterator it = items.begin();
0064     while (it != items.end()) {
0065         if ((*it)->isProjectRoot() || !(*it)->parent()->folder()) {
0066             it = items.erase(it);
0067         } else {
0068             ++it;
0069         }
0070     }
0071     if (items.isEmpty()) {
0072         return ret;
0073     }
0074 
0075     auto* action = new QAction(QIcon::fromTheme(QStringLiteral("view-filter")),
0076                                i18ncp("@action:inmenu", "Exclude Item from Project",
0077                                      "Exclude Items from Project",
0078                                      items.size()), parent);
0079     action->setData(QVariant::fromValue(items));
0080     connect(action, &QAction::triggered, this, &ProjectFilterProvider::addFilterFromContextMenu);
0081     ret.addAction(ContextMenuExtension::FileGroup, action);
0082     return ret;
0083 }
0084 
0085 void ProjectFilterProvider::addFilterFromContextMenu()
0086 {
0087     auto* action = qobject_cast<QAction*>(sender());
0088     Q_ASSERT(action);
0089     const QList<ProjectBaseItem*> items = action->data().value<QList<ProjectBaseItem*>>();
0090     QHash<IProject*, SerializedFilters> changedProjectFilters;
0091     for (ProjectBaseItem* item : items) {
0092         auto filterIt = changedProjectFilters.find(item->project());
0093         if (filterIt == changedProjectFilters.end()) {
0094             filterIt = changedProjectFilters.insert(item->project(), readFilters(item->project()->projectConfiguration()));
0095         }
0096         SerializedFilters& filters = *filterIt;
0097         Path path;
0098         if (item->target()) {
0099             path = Path(item->parent()->path(), item->text());
0100         } else {
0101             path = item->path();
0102         }
0103         filters << SerializedFilter(QLatin1Char('/') + item->project()->path().relativePath(path),
0104                                     item->folder() ? Filter::Folders : Filter::Files);
0105     }
0106     QHash< IProject*, SerializedFilters >::const_iterator it = changedProjectFilters.constBegin();
0107     while (it != changedProjectFilters.constEnd()) {
0108         writeFilters(it.value(), it.key()->projectConfiguration());
0109         m_filters[it.key()] = deserialize(it.value());
0110         emit filterChanged(this, it.key());
0111         ++it;
0112     }
0113 
0114     KMessageBox::information(ICore::self()->uiController()->activeMainWindow(),
0115                              i18np("A filter for the item was added. To undo, use the project filter settings.",
0116                                    "A filter for the items was added. To undo, use the project filter settings.",
0117                                    items.size()), i18nc("@title:window", "Project Filter Added"), QStringLiteral("projectfilter-addfromctxmenu"));
0118 }
0119 
0120 void ProjectFilterProvider::updateProjectFilters(IProject* project)
0121 {
0122     Filters newFilters = deserialize(readFilters(project->projectConfiguration()));
0123     Filters& filters = m_filters[project];
0124     if (filters != newFilters) {
0125         qCDebug(PLUGIN_PROJECTFILTER) << "project filter changed:" << project->name();
0126         filters = newFilters;
0127         emit filterChanged(this, project);
0128     }
0129 }
0130 
0131 void ProjectFilterProvider::projectAboutToBeOpened(IProject* project)
0132 {
0133     m_filters[project] = deserialize(readFilters(project->projectConfiguration()));
0134 }
0135 
0136 void ProjectFilterProvider::projectClosing(IProject* project)
0137 {
0138     m_filters.remove(project);
0139 }
0140 
0141 int ProjectFilterProvider::perProjectConfigPages() const
0142 {
0143     return 1;
0144 }
0145 
0146 ConfigPage* ProjectFilterProvider::perProjectConfigPage(int i, const ProjectConfigOptions& options, QWidget* parent)
0147 {
0148     return i == 0 ? new ProjectFilterConfigPage(this, options, parent) : nullptr;
0149 }
0150 
0151 #include "projectfilterprovider.moc"
0152 #include "moc_projectfilterprovider.cpp"