File indexing completed on 2024-04-28 04:39:10
0001 /* 0002 SPDX-FileCopyrightText: 2013 Aleix Pol <aleixpol@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "vcsoverlayproxymodel.h" 0008 #include <projectchangesmodel.h> 0009 #include <interfaces/icore.h> 0010 #include <interfaces/iprojectcontroller.h> 0011 #include <interfaces/iproject.h> 0012 #include <interfaces/iruncontroller.h> 0013 #include <interfaces/iplugin.h> 0014 #include <vcs/interfaces/ibranchingversioncontrol.h> 0015 #include <vcs/vcsjob.h> 0016 #include <project/projectmodel.h> 0017 #include <util/path.h> 0018 0019 #include <KLocalizedString> 0020 0021 #include <QPointer> 0022 0023 0024 using namespace KDevelop; 0025 0026 using SafeProjectPointer = QPointer<KDevelop::IProject>; 0027 0028 VcsOverlayProxyModel::VcsOverlayProxyModel(QObject* parent): QIdentityProxyModel(parent) 0029 { 0030 connect(ICore::self()->projectController(), &IProjectController::projectOpened, 0031 this, &VcsOverlayProxyModel::addProject); 0032 connect(ICore::self()->projectController(), &IProjectController::projectClosing, 0033 this, &VcsOverlayProxyModel::removeProject); 0034 0035 const auto projects = ICore::self()->projectController()->projects(); 0036 for (const auto project : projects) { 0037 addProject(project); 0038 } 0039 } 0040 0041 QVariant VcsOverlayProxyModel::data(const QModelIndex& proxyIndex, int role) const 0042 { 0043 if(role == VcsStatusRole) { 0044 if (!proxyIndex.parent().isValid()) { 0045 auto* p = qobject_cast<IProject*>(proxyIndex.data(ProjectModel::ProjectRole).value<QObject*>()); 0046 return m_branchName.value(p); 0047 } else { 0048 ProjectChangesModel* model = ICore::self()->projectController()->changesModel(); 0049 const QUrl url = proxyIndex.data(ProjectModel::UrlRole).toUrl(); 0050 const auto idx = model->match(model->index(0, 0), ProjectChangesModel::UrlRole, url, 1, Qt::MatchExactly).value(0); 0051 return idx.sibling(idx.row(), 1).data(Qt::DisplayRole); 0052 } 0053 } else 0054 return QIdentityProxyModel::data(proxyIndex, role); 0055 } 0056 0057 void VcsOverlayProxyModel::addProject(IProject* p) 0058 { 0059 IPlugin* plugin = p->versionControlPlugin(); 0060 if(!plugin) 0061 return; 0062 0063 // TODO: Show revision in case we're in "detached" state 0064 auto* branchingExtension = plugin->extension<KDevelop::IBranchingVersionControl>(); 0065 if(branchingExtension) { 0066 const QUrl url = p->path().toUrl(); 0067 branchingExtension->registerRepositoryForCurrentBranchChanges(url); 0068 //can't use new signal/slot syntax here, IBranchingVersionControl is not a QObject 0069 connect(plugin, SIGNAL(repositoryBranchChanged(QUrl)), SLOT(repositoryBranchChanged(QUrl))); 0070 repositoryBranchChanged(url); 0071 } 0072 } 0073 0074 void VcsOverlayProxyModel::repositoryBranchChanged(const QUrl& url) 0075 { 0076 const QList<IProject*> allProjects = ICore::self()->projectController()->projects(); 0077 for (IProject* project : allProjects) { 0078 const bool isExactMatch = url.matches(project->path().toUrl(), QUrl::StripTrailingSlash); 0079 const bool isParentOf = url.isParentOf(project->path().toUrl()); 0080 if (isParentOf || isExactMatch) { 0081 // example projects in KDevelop: 0082 // - /path/to/mygitrepo/: isParentOf=0 isExactMatch=1, 0083 // - /path/to/mygitrepo/myproject: isParentOf=1 isExactMatch=0 0084 // - /path/to/norepo: isParentOf=0 isExactMatch=0 0085 // isParentOf=1 isExactMatch=1 is not a valid combination 0086 0087 IPlugin* v = project->versionControlPlugin(); 0088 Q_ASSERT(!isExactMatch || v); // project url == 'change' url => project should be associated with a VCS plugin 0089 if (!v) { 0090 continue; 0091 } 0092 0093 auto* branching = v->extension<IBranchingVersionControl>(); 0094 Q_ASSERT(branching); 0095 VcsJob* job = branching->currentBranch(url); 0096 connect(job, &VcsJob::resultsReady, this, &VcsOverlayProxyModel::branchNameReady); 0097 job->setProperty("project", QVariant::fromValue<SafeProjectPointer>(project)); 0098 ICore::self()->runController()->registerJob(job); 0099 } 0100 } 0101 } 0102 0103 void VcsOverlayProxyModel::branchNameReady(KDevelop::VcsJob* job) 0104 { 0105 const QString noBranchStr = i18nc("Version control: Currently not on a branch", "(no branch)"); 0106 0107 if(job->status()==VcsJob::JobSucceeded) { 0108 SafeProjectPointer p = job->property("project").value<SafeProjectPointer>(); 0109 QModelIndex index = indexFromProject(p); 0110 if(index.isValid()) { 0111 IProject* project = p.data(); 0112 const auto branchName = job->fetchResults().toString(); 0113 m_branchName[project] = branchName.isEmpty() ? noBranchStr : branchName; 0114 emit dataChanged(index, index); 0115 } 0116 } 0117 } 0118 0119 void VcsOverlayProxyModel::removeProject(IProject* p) 0120 { 0121 m_branchName.remove(p); 0122 } 0123 0124 QModelIndex VcsOverlayProxyModel::indexFromProject(QObject* project) 0125 { 0126 for(int i=0; i<rowCount(); i++) { 0127 QModelIndex idx = index(i,0); 0128 if(idx.data(ProjectModel::ProjectRole).value<QObject*>()==project) { 0129 return idx; 0130 } 0131 } 0132 return QModelIndex(); 0133 } 0134 0135 #include "moc_vcsoverlayproxymodel.cpp"