File indexing completed on 2024-05-05 04:41:03

0001 /*
0002     SPDX-FileCopyrightText: 2010 Aleix Pol Gonzalez <aleixpol@kde.org>
0003 
0004     SPDX-License-Identifier: LGPL-2.0-or-later
0005 */
0006 
0007 #include "vcschangesview.h"
0008 #include <interfaces/icore.h>
0009 #include <interfaces/context.h>
0010 #include <interfaces/iproject.h>
0011 #include <interfaces/idocumentcontroller.h>
0012 #include <interfaces/iplugincontroller.h>
0013 #include <interfaces/iprojectcontroller.h>
0014 #include <interfaces/contextmenuextension.h>
0015 #include <vcs/vcsstatusinfo.h>
0016 #include <project/projectchangesmodel.h>
0017 #include <project/projectmodel.h>
0018 #include <project/projectutils.h>
0019 
0020 #include <QIcon>
0021 #include <QMenu>
0022 #include <QPointer>
0023 
0024 #include <KActionCollection>
0025 #include <KLocalizedString>
0026 
0027 #include "vcschangesviewplugin.h"
0028 
0029 using namespace KDevelop;
0030 
0031 VcsChangesView::VcsChangesView(VcsProjectIntegrationPlugin* plugin, QWidget* parent)
0032     : QTreeView(parent)
0033 {
0034     setRootIsDecorated(false);
0035     setEditTriggers(QAbstractItemView::NoEditTriggers);
0036     setSelectionMode(ContiguousSelection);
0037     setContextMenuPolicy(Qt::CustomContextMenu);
0038     setTextElideMode(Qt::ElideLeft);
0039     setWordWrap(true);
0040     setWindowIcon(QIcon::fromTheme(QStringLiteral("exchange-positions"), windowIcon()));
0041     
0042     connect(this, &VcsChangesView::customContextMenuRequested, this, &VcsChangesView::popupContextMenu);
0043 
0044     const auto pluginActions = plugin->actionCollection()->actions();
0045     for (QAction* action : pluginActions) {
0046         addAction(action);
0047     }
0048     
0049     QAction* action = plugin->actionCollection()->action(QStringLiteral("locate_document"));
0050     connect(action, &QAction::triggered, this, &VcsChangesView::selectCurrentDocument);
0051     connect(this, &VcsChangesView::doubleClicked, this, &VcsChangesView::openSelected);
0052 }
0053 
0054 static void appendActions(QMenu* menu, const QList<QAction*>& actions)
0055 {
0056     menu->addSeparator();
0057     menu->addActions(actions);
0058 }
0059 
0060 void VcsChangesView::popupContextMenu( const QPoint &pos )
0061 {
0062     QList<QUrl> urls;
0063     QList<IProject*> projects;
0064     const QModelIndexList selectionIdxs = selectedIndexes();
0065     if(selectionIdxs.isEmpty())
0066         return;
0067     
0068     for (const QModelIndex& idx : selectionIdxs) {
0069         if(idx.column()==0) {
0070             if(idx.parent().isValid())
0071                 urls += idx.data(KDevelop::VcsFileChangesModel::VcsStatusInfoRole).value<VcsStatusInfo>().url();
0072             else {
0073                 IProject* project = ICore::self()->projectController()->findProjectByName(idx.data(ProjectChangesModel::ProjectNameRole).toString());
0074                 if (project) {
0075                     projects += project;
0076                 } else {
0077                     qWarning() << "Couldn't find a project for project: " << idx.data(ProjectChangesModel::ProjectNameRole).toString();
0078                 }
0079             }
0080         }
0081     }
0082 
0083     QPointer<QMenu> menu = new QMenu(this);
0084     QAction* refreshAction = menu->addAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18nc("@action:inmenu", "Refresh"));
0085     QList<ContextMenuExtension> extensions;
0086     if(!urls.isEmpty()) {
0087         KDevelop::FileContext context(urls);
0088         extensions = ICore::self()->pluginController()->queryPluginsForContextMenuExtensions(&context, menu);
0089     } else {
0090         QList<ProjectBaseItem*> items;
0091         items.reserve(projects.size());
0092         for (IProject* p : qAsConst(projects)) {
0093             items += p->projectItem();
0094         }
0095 
0096         KDevelop::ProjectItemContextImpl context(items);
0097         extensions = ICore::self()->pluginController()->queryPluginsForContextMenuExtensions(&context, menu);
0098         
0099     }
0100 
0101     QList<QAction*> buildActions;
0102     QList<QAction*> vcsActions;
0103     QList<QAction*> extActions;
0104     QList<QAction*> projectActions;
0105     QList<QAction*> fileActions;
0106     QList<QAction*> runActions;
0107     for (const ContextMenuExtension& ext : qAsConst(extensions)) {
0108         buildActions += ext.actions(ContextMenuExtension::BuildGroup);
0109         fileActions += ext.actions(ContextMenuExtension::FileGroup);
0110         projectActions += ext.actions(ContextMenuExtension::ProjectGroup);
0111         vcsActions += ext.actions(ContextMenuExtension::VcsGroup);
0112         extActions += ext.actions(ContextMenuExtension::ExtensionGroup);
0113         runActions += ext.actions(ContextMenuExtension::RunGroup);
0114     }
0115 
0116     appendActions(menu, buildActions);
0117     appendActions(menu, runActions );
0118     appendActions(menu, fileActions);
0119     appendActions(menu, vcsActions);
0120     appendActions(menu, extActions);
0121     appendActions(menu, projectActions);
0122 
0123     if ( !menu->isEmpty() ) {
0124         QAction* res = menu->exec(viewport()->mapToGlobal(pos));
0125         if(res == refreshAction) {
0126             if(!urls.isEmpty())
0127                 emit reload(urls);
0128             else
0129                 emit reload(projects);
0130         }
0131     }
0132     delete menu;
0133 }
0134 
0135 void VcsChangesView::selectCurrentDocument()
0136 {
0137     IDocument* doc = ICore::self()->documentController()->activeDocument();
0138     if(!doc)
0139         return;
0140     
0141     QUrl url = doc->url();
0142     IProject* p = ICore::self()->projectController()->findProjectForUrl(url);
0143     QModelIndex idx = (p ?
0144         model()->match(model()->index(0, 0), ProjectChangesModel::UrlRole,
0145                        url, 1, Qt::MatchExactly).value(0) :
0146         QModelIndex());
0147     if(idx.isValid()) {
0148         expand(idx.parent());
0149         setCurrentIndex(idx);
0150     } else
0151         collapseAll();
0152 }
0153 
0154 void VcsChangesView::setModel(QAbstractItemModel* model)
0155 {
0156     connect(model, &QAbstractItemModel::rowsInserted, this, &VcsChangesView::expand);
0157     QTreeView::setModel(model);
0158 }
0159 
0160 void VcsChangesView::openSelected(const QModelIndex& index)
0161 {
0162     if(!index.parent().isValid()) //then it's a project
0163         return;
0164     QModelIndex idx = index.sibling(index.row(), 1);
0165     VcsStatusInfo info = idx.data(ProjectChangesModel::VcsStatusInfoRole).value<VcsStatusInfo>();
0166     QUrl url = info.url();
0167     
0168     ICore::self()->documentController()->openDocument(url);
0169 }
0170 
0171 #include "moc_vcschangesview.cpp"