File indexing completed on 2024-05-12 04:38:54

0001 /*
0002     SPDX-FileCopyrightText: 2008 Evgeniy Ivanov <powerfox@kde.ru>
0003     SPDX-FileCopyrightText: 2012 Aleix Pol Gonzalez <aleixpol@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 
0008 #include "brancheslistmodel.h"
0009 #include "debug.h"
0010 #include <vcs/interfaces/ibranchingversioncontrol.h>
0011 #include <vcs/vcsjob.h>
0012 #include <vcs/vcsrevision.h>
0013 #include <interfaces/icore.h>
0014 #include <interfaces/iprojectcontroller.h>
0015 #include <interfaces/iproject.h>
0016 #include <interfaces/iplugin.h>
0017 #include <interfaces/iruncontroller.h>
0018 #include "util/path.h"
0019 
0020 #include <QIcon>
0021 
0022 #include <KMessageBox>
0023 #include <KMessageBox_KDevCompat>
0024 #include <KLocalizedString>
0025 
0026 using namespace std;
0027 using namespace KDevelop;
0028 
0029 class KDevelop::BranchesListModelPrivate
0030 {
0031     public:
0032         BranchesListModelPrivate()
0033         {
0034         }
0035 
0036         IBranchingVersionControl * dvcsplugin;
0037         QUrl repo;
0038 };
0039 
0040 class BranchItem : public QStandardItem
0041 {
0042     public:
0043         explicit BranchItem(const QString& name, bool current=false) :
0044             QStandardItem(name)
0045         {
0046             setEditable(true);
0047             setCurrent(current);
0048         }
0049 
0050         void setCurrent(bool current)
0051         {
0052             setData(current, BranchesListModel::CurrentRole);
0053             setIcon(current ? QIcon::fromTheme(QStringLiteral("arrow-right")) : QIcon());
0054         }
0055 
0056         void setData(const QVariant& value, int role = Qt::UserRole + 1) override
0057         {
0058             if(role==Qt::EditRole && value.toString()!=text()) {
0059                 QString newBranch = value.toString();
0060 
0061                 auto* bmodel = qobject_cast<BranchesListModel*>(model());
0062                 if(!bmodel->findItems(newBranch).isEmpty())
0063                 {
0064                     KMessageBox::error(nullptr, i18n("Branch \"%1\" already exists.", newBranch));
0065                     return;
0066                 }
0067 
0068                 int ret = KMessageBox::warningTwoActions(
0069                     nullptr, i18n("Are you sure you want to rename \"%1\" to \"%2\"?", text(), newBranch), {},
0070                     KGuiItem(i18nc("@action:button", "Rename"), QStringLiteral("edit-rename")),
0071                     KStandardGuiItem::cancel());
0072                 if (ret == KMessageBox::SecondaryAction) {
0073                     return; // ignore event
0074                 }
0075 
0076                 KDevelop::VcsJob *branchJob = bmodel->interface()->renameBranch(bmodel->repository(), newBranch, text());
0077                 ret = branchJob->exec();
0078                 qCDebug(VCS) << "Renaming " << text() << " to " << newBranch << ':' << ret;
0079                 if (!ret) {
0080                     return; // ignore event
0081                 }
0082             }
0083 
0084             QStandardItem::setData(value, role);
0085         }
0086 };
0087 
0088 static QVariant runSynchronously(KDevelop::VcsJob* job)
0089 {
0090     job->setVerbosity(KDevelop::OutputJob::Silent);
0091     QVariant ret;
0092     if(job->exec() && job->status()==KDevelop::VcsJob::JobSucceeded) {
0093         ret = job->fetchResults();
0094     }
0095     delete job;
0096     return ret;
0097 }
0098 
0099 BranchesListModel::BranchesListModel(QObject* parent)
0100     : QStandardItemModel(parent)
0101     , d_ptr(new BranchesListModelPrivate())
0102 {
0103 }
0104 
0105 BranchesListModel::~BranchesListModel()
0106 {
0107 }
0108 
0109 QHash<int, QByteArray> BranchesListModel::roleNames() const
0110 {
0111     auto roles = QAbstractItemModel::roleNames();
0112     roles.insert(CurrentRole, "isCurrent");
0113     return roles;
0114 }
0115 
0116 void BranchesListModel::createBranch(const QString& baseBranch, const QString& newBranch)
0117 {
0118     Q_D(BranchesListModel);
0119 
0120     qCDebug(VCS) << "Creating " << baseBranch << " based on " << newBranch;
0121     KDevelop::VcsRevision rev;
0122     rev.setRevisionValue(baseBranch, KDevelop::VcsRevision::GlobalNumber);
0123     KDevelop::VcsJob* branchJob = d->dvcsplugin->branch(d->repo, rev, newBranch);
0124 
0125     qCDebug(VCS) << "Adding new branch";
0126     if (branchJob->exec())
0127         appendRow(new BranchItem(newBranch));
0128 }
0129 
0130 void BranchesListModel::removeBranch(const QString& branch)
0131 {
0132     Q_D(BranchesListModel);
0133 
0134     KDevelop::VcsJob *branchJob = d->dvcsplugin->deleteBranch(d->repo, branch);
0135 
0136     qCDebug(VCS) << "Removing branch:" << branch;
0137     if (branchJob->exec()) {
0138         const QList<QStandardItem*> items = findItems(branch);
0139         for (QStandardItem* item : items) {
0140             removeRow(item->row());
0141         }
0142     }
0143 }
0144 
0145 QUrl BranchesListModel::repository() const
0146 {
0147     Q_D(const BranchesListModel);
0148 
0149     return d->repo;
0150 }
0151 
0152 KDevelop::IBranchingVersionControl* BranchesListModel::interface() const
0153 {
0154     Q_D(const BranchesListModel);
0155 
0156     return d->dvcsplugin;
0157 }
0158 
0159 void BranchesListModel::initialize(KDevelop::IBranchingVersionControl* branching, const QUrl& r)
0160 {
0161     Q_D(BranchesListModel);
0162 
0163     d->dvcsplugin = branching;
0164     d->repo = r;
0165     refresh();
0166 }
0167 
0168 void BranchesListModel::refresh()
0169 {
0170     Q_D(BranchesListModel);
0171 
0172     const QStringList branches = runSynchronously(d->dvcsplugin->branches(d->repo)).toStringList();
0173     QString curBranch = runSynchronously(d->dvcsplugin->currentBranch(d->repo)).toString();
0174 
0175     for (const QString& branch : branches) {
0176         appendRow(new BranchItem(branch, branch == curBranch));
0177     }
0178 }
0179 
0180 void BranchesListModel::resetCurrent()
0181 {
0182     refresh();
0183     emit currentBranchChanged();
0184 }
0185 
0186 QString BranchesListModel::currentBranch() const
0187 {
0188     Q_D(const BranchesListModel);
0189 
0190     return runSynchronously(d->dvcsplugin->currentBranch(d->repo)).toString();
0191 }
0192 
0193 KDevelop::IProject* BranchesListModel::project() const
0194 {
0195     Q_D(const BranchesListModel);
0196 
0197     return KDevelop::ICore::self()->projectController()->findProjectForUrl(d->repo);
0198 }
0199 
0200 void BranchesListModel::setProject(KDevelop::IProject* p)
0201 {
0202     if(!p || !p->versionControlPlugin()) {
0203         qCDebug(VCS) << "null or invalid project" << p;
0204         return;
0205     }
0206 
0207     auto* branching = p->versionControlPlugin()->extension<KDevelop::IBranchingVersionControl>();
0208     if(branching) {
0209         initialize(branching, p->path().toUrl());
0210     } else
0211         qCDebug(VCS) << "not a branching vcs project" << p->name();
0212 }
0213 
0214 void BranchesListModel::setCurrentBranch(const QString& branch)
0215 {
0216     Q_D(BranchesListModel);
0217 
0218     KDevelop::VcsJob* job = d->dvcsplugin->switchBranch(d->repo, branch);
0219     connect(job, &VcsJob::finished, this, &BranchesListModel::currentBranchChanged);
0220     KDevelop::ICore::self()->runController()->registerJob(job);
0221 }
0222 
0223 #include "moc_brancheslistmodel.cpp"