• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdevelop API Reference
  • KDE Home
  • Contact Us
 

kdevplatform/vcs

  • sources
  • kfour-appscomplete
  • kdevelop
  • kdevplatform
  • vcs
  • dvcs
  • ui
branchmanager.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright 2008 Evgeniy Ivanov <[email protected]> *
3  * *
4  * This program is free software; you can redistribute it and/or *
5  * modify it under the terms of the GNU General Public License as *
6  * published by the Free Software Foundation; either version 2 of *
7  * the License or (at your option) version 3 or any later version *
8  * accepted by the membership of KDE e.V. (or its successor approved *
9  * by the membership of KDE e.V.), which shall act as a proxy *
10  * defined in Section 14 of version 3 of the license. *
11  * *
12  * This program is distributed in the hope that it will be useful, *
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
15  * GNU General Public License for more details. *
16  * *
17  * You should have received a copy of the GNU General Public License *
18  * along with this program. If not, see <http://www.gnu.org/licenses/>. *
19  ***************************************************************************/
20 
21 #include "branchmanager.h"
22 
23 #include <QInputDialog>
24 
25 #include <KMessageBox>
26 #include <KLocalizedString>
27 
28 #include "../dvcsplugin.h"
29 #include <vcs/vcsjob.h>
30 #include <vcs/models/brancheslistmodel.h>
31 #include "ui_branchmanager.h"
32 #include "debug.h"
33 #include "widgets/vcsdiffpatchsources.h"
34 
35 #include <interfaces/icore.h>
36 #include <interfaces/iruncontroller.h>
37 #include <interfaces/iuicontroller.h>
38 #include <QDialogButtonBox>
39 #include <QPushButton>
40 #include <QVBoxLayout>
41 #include <QSortFilterProxyModel>
42 #include <KParts/MainWindow>
43 
44 using namespace KDevelop;
45 
46 BranchManager::BranchManager(const QString& repository, KDevelop::DistributedVersionControlPlugin* executor, QWidget *parent)
47  : QDialog(parent)
48  , m_repository(repository)
49  , m_dvcPlugin(executor)
50 {
51  setWindowTitle(i18nc("@title:window", "Branch Manager"));
52 
53  auto* mainWidget = new QWidget(this);
54  auto *mainLayout = new QVBoxLayout(this);
55  mainLayout->addWidget(mainWidget);
56 
57  m_ui = new Ui::BranchDialogBase;
58  auto* w = new QWidget(this);
59  m_ui->setupUi(w);
60  mainLayout->addWidget(w);
61 
62  auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
63  connect(buttonBox, &QDialogButtonBox::accepted, this, &BranchManager::accept);
64  connect(buttonBox, &QDialogButtonBox::rejected, this, &BranchManager::reject);
65  mainLayout->addWidget(buttonBox);
66 
67  m_model = new BranchesListModel(this);
68  m_model->initialize(m_dvcPlugin, QUrl::fromLocalFile(repository));
69 
70  // Filter Model
71  m_filterModel = new QSortFilterProxyModel();
72  m_filterModel->setSourceModel(m_model);
73  m_filterModel->setFilterWildcard(QString());
74  m_filterModel->sort(0, Qt::AscendingOrder);
75 
76  //Changes in filter edit trigger filtering
77  connect(m_ui->branchFilterEdit,
78  &QLineEdit::textChanged,
79  m_filterModel,
80  &QSortFilterProxyModel::setFilterWildcard);
81 
82  m_ui->branchView->setModel(m_filterModel);
83 
84  QString branchName = m_model->currentBranch();
85  // apply initial selection
86  QList< QStandardItem* > items = m_model->findItems(branchName);
87  if (!items.isEmpty()) {
88  m_ui->branchView->setCurrentIndex(items.first()->index());
89  }
90 
91  connect(m_ui->newButton, &QPushButton::clicked, this, &BranchManager::createBranch);
92  connect(m_ui->deleteButton, &QPushButton::clicked, this, &BranchManager::deleteBranch);
93  connect(m_ui->renameButton, &QPushButton::clicked, this, &BranchManager::renameBranch);
94  connect(m_ui->checkoutButton, &QPushButton::clicked, this, &BranchManager::checkoutBranch);
95 
96  // checkout branch on double-click
97  connect(m_ui->branchView, &QListView::doubleClicked, this, &BranchManager::checkoutBranch);
98 
99  connect(m_ui->mergeButton, &QPushButton::clicked, this, &BranchManager::mergeBranch);
100  connect(m_ui->diffButton, &QPushButton::clicked, this, &BranchManager::diffFromBranch);
101 }
102 
103 BranchManager::~BranchManager()
104 {
105  delete m_ui;
106 }
107 
108 void BranchManager::createBranch()
109 {
110  const QModelIndex currentBranchIdx = m_ui->branchView->currentIndex();
111  if (!currentBranchIdx.isValid()) {
112  KMessageBox::messageBox(this, KMessageBox::Error,
113  i18n("You must select a base branch from the list before creating a new branch."));
114  return;
115  }
116  QString baseBranch = currentBranchIdx.data().toString();
117  bool branchNameEntered = false;
118  QString newBranch = QInputDialog::getText(this, i18nc("@title:window", "New Branch"), i18nc("@label:textbox", "Name of the new branch:"),
119  QLineEdit::Normal, QString(), &branchNameEntered);
120  if (!branchNameEntered)
121  return;
122 
123  if (!m_model->findItems(newBranch).isEmpty())
124  {
125  KMessageBox::messageBox(this, KMessageBox::Sorry,
126  i18n("Branch \"%1\" already exists.\n"
127  "Please, choose another name.",
128  newBranch));
129  }
130  else
131  m_model->createBranch(baseBranch, newBranch);
132 }
133 
134 void BranchManager::deleteBranch()
135 {
136  QString baseBranch = m_ui->branchView->selectionModel()->selection().indexes().first().data().toString();
137 
138  if (baseBranch == m_model->currentBranch())
139  {
140  KMessageBox::messageBox(this, KMessageBox::Sorry,
141  i18n("Currently at the branch \"%1\".\n"
142  "To remove it, please change to another branch.",
143  baseBranch));
144  return;
145  }
146 
147  int ret = KMessageBox::messageBox(this, KMessageBox::WarningYesNo,
148  i18n("Are you sure you want to irreversibly remove the branch '%1'?", baseBranch));
149  if (ret == KMessageBox::Yes)
150  m_model->removeBranch(baseBranch);
151 }
152 
153 void BranchManager::renameBranch()
154 {
155  QModelIndex currentIndex = m_ui->branchView->currentIndex();
156  if (!currentIndex.isValid())
157  return;
158 
159  m_ui->branchView->edit(currentIndex);
160 }
161 
162 void BranchManager::checkoutBranch()
163 {
164  QString branch = m_ui->branchView->currentIndex().data().toString();
165  if (branch == m_model->currentBranch())
166  {
167  KMessageBox::messageBox(this, KMessageBox::Sorry,
168  i18n("Already on branch \"%1\"\n",
169  branch));
170  return;
171  }
172 
173  qCDebug(VCS) << "Switching to" << branch << "in" << m_repository;
174  KDevelop::VcsJob *branchJob = m_dvcPlugin->switchBranch(QUrl::fromLocalFile(m_repository), branch);
175 // connect(branchJob, SIGNAL(finished(KJob*)), m_model, SIGNAL(resetCurrent()));
176 
177  ICore::self()->runController()->registerJob(branchJob);
178  close();
179 }
180 
181 void BranchManager::mergeBranch()
182 {
183  const QModelIndex branchToMergeIdx = m_ui->branchView->currentIndex();
184 
185  if (branchToMergeIdx.isValid()) {
186  QString branchToMerge = branchToMergeIdx.data().toString();
187 
188  if (m_model->findItems(branchToMerge).isEmpty()) {
189  KMessageBox::messageBox(this, KMessageBox::Sorry, i18n("Branch \"%1\" doesn't exists.\n"
190  "Please, choose another name.",
191  branchToMerge));
192  } else {
193  KDevelop::VcsJob* branchJob = m_dvcPlugin->mergeBranch(QUrl::fromLocalFile(m_repository), branchToMerge);
194  ICore::self()->runController()->registerJob(branchJob);
195  close();
196  }
197  } else {
198  KMessageBox::messageBox(this, KMessageBox::Error,
199  i18n("You must select a branch to merge into current one from the list."));
200  }
201 }
202 
203 // adapted from VCSStandardDiffUpdater
204 class VCSBranchDiffUpdater : public VCSDiffUpdater {
205 public:
206  VCSBranchDiffUpdater(const QString& repo, const QString& src, KDevelop::DistributedVersionControlPlugin* vcs);
207  ~VCSBranchDiffUpdater() override;
208  KDevelop::VcsDiff update() const override;
209  KDevelop::IBasicVersionControl* vcs() const override { return m_vcs; }
210  QUrl url() const override { return QUrl::fromLocalFile(m_repository); }
211 private:
212  const QString m_repository;
213  const QString m_src;
214  KDevelop::DistributedVersionControlPlugin* m_vcs;
215 };
216 
217 VCSBranchDiffUpdater::VCSBranchDiffUpdater(const QString& repo, const QString& src,
218  KDevelop::DistributedVersionControlPlugin* vcs)
219  : m_repository(repo)
220  , m_src(src)
221  , m_vcs(vcs)
222 {
223 }
224 
225 VCSBranchDiffUpdater::~VCSBranchDiffUpdater() {
226 }
227 
228 VcsDiff VCSBranchDiffUpdater::update() const
229 {
230  VcsRevision srcRev;
231  srcRev.setRevisionValue(m_src, KDevelop::VcsRevision::GlobalNumber);
232  // see comment in BranchManager::diffFromBranch()
233  const auto destRev = VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Working);
234  QScopedPointer<VcsJob> diffJob(m_vcs->diff(QUrl::fromLocalFile(m_repository), srcRev, destRev));
235  const bool success = diffJob ? diffJob->exec() : false;
236  if (!success) {
237  KMessageBox::error(nullptr, i18n("Could not create a patch for the current version."));
238  return {};
239  }
240 
241  return diffJob->fetchResults().value<VcsDiff>();
242 }
243 
244 void BranchManager::diffFromBranch()
245 {
246  const auto dest = m_model->currentBranch();
247  const auto src = m_ui->branchView->currentIndex().data().toString();
248  if (src == dest) {
249  KMessageBox::messageBox(this, KMessageBox::Information, i18n("Already on branch \"%1\"\n", src));
250  return;
251  }
252 
253  VcsRevision srcRev;
254  srcRev.setRevisionValue(src, KDevelop::VcsRevision::GlobalNumber);
255  // We have two options here:
256  // * create a regular VcsRevision to represent the last commit on the current branch or
257  // * create a special branch to reflect the staging area. I chose this one.
258  // If the staging area is clean it automatically defaults to the first option.
259  const auto destRev = VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Working);
260  const auto job = m_dvcPlugin->diff(QUrl::fromLocalFile(m_repository), srcRev, destRev);
261  connect(job, &VcsJob::finished, this, &BranchManager::diffJobFinished);
262  m_dvcPlugin->core()->runController()->registerJob(job);
263 }
264 
265 void BranchManager::diffJobFinished(KJob* job)
266 {
267  auto vcsjob = qobject_cast<KDevelop::VcsJob*>(job);
268  Q_ASSERT(vcsjob);
269 
270  if (vcsjob->status() != KDevelop::VcsJob::JobSucceeded) {
271  KMessageBox::error(ICore::self()->uiController()->activeMainWindow(), vcsjob->errorString(),
272  i18nc("@titlew:indow", "Unable to Retrieve Diff"));
273  return;
274  }
275 
276  auto diff = vcsjob->fetchResults().value<KDevelop::VcsDiff>();
277  if(diff.isEmpty()){
278  KMessageBox::information(ICore::self()->uiController()->activeMainWindow(),
279  i18n("There are no committed differences."),
280  i18nc("@title:window", "VCS Support"));
281  return;
282  }
283 
284  auto patch = new VCSDiffPatchSource(new VCSBranchDiffUpdater(m_repository,
285  m_ui->branchView->currentIndex().data().toString(), m_dvcPlugin));
286  showVcsDiff(patch);
287  close();
288 }
QList::first
T & first()
QAbstractItemView::doubleClicked
void doubleClicked(const QModelIndex &index)
QVBoxLayout
VCSDiffUpdater::update
virtual KDevelop::VcsDiff update() const =0
QWidget::QWidget
QWidget(QWidget *parent, QFlags< Qt::WindowType > f)
QDialog::reject
virtual void reject()
KDevelop::IBranchingVersionControl::switchBranch
virtual VcsJob * switchBranch(const QUrl &repository, const QString &branchName)=0
Switches to the desired branch inside the specified repository.
QUrl
KDevelop::BranchesListModel::initialize
void initialize(KDevelop::IBranchingVersionControl *dvcsplugin, const QUrl &repo)
Definition: brancheslistmodel.cpp:170
QAbstractButton::clicked
void clicked(bool checked)
QWidget
VCSDiffPatchSource
Definition: vcsdiffpatchsources.h:66
KDevelop::IBasicVersionControl::diff
virtual VcsJob * diff(const QUrl &fileOrDirectory, const VcsRevision &srcRevision, const VcsRevision &dstRevision, IBasicVersionControl::RecursionMode recursion=IBasicVersionControl::Recursive)=0
Retrieves a diff between two revisions of a file.
KDevelop::VcsDiff
Definition: vcsdiff.h:37
KDevelop::IBasicVersionControl
This is the basic interface that all Version Control or Source Code Management plugins need to implem...
Definition: ibasicversioncontrol.h:52
showVcsDiff
bool showVcsDiff(IPatchSource *vcsDiff)
Sends the diff to the patch-review plugin.
Definition: vcsdiffpatchsources.cpp:291
BranchManager::~BranchManager
~BranchManager() override
Definition: branchmanager.cpp:102
KDevelop::BranchesListModel
Definition: brancheslistmodel.h:52
QSortFilterProxyModel::sort
virtual void sort(int column, Qt::SortOrder order)
KDevelop::VcsRevision
Encapsulates a vcs revision number, date or range of revisions.
Definition: vcsrevision.h:66
VCSDiffUpdater::url
virtual QUrl url() const =0
QWidget::close
bool close()
QSortFilterProxyModel::setSourceModel
virtual void setSourceModel(QAbstractItemModel *sourceModel)
QList
Definition: vcsannotationmodel.h:31
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
KDevelop::BranchesListModel::createBranch
Q_INVOKABLE void createBranch(const QString &baseBranch, const QString &newBranch)
Definition: brancheslistmodel.cpp:127
QStandardItemModel::findItems
QList< QStandardItem * > findItems(const QString &text, QFlags< Qt::MatchFlag > flags, int column) const
KDevelop::VcsRevision::setRevisionValue
void setRevisionValue(const QVariant &rev, RevisionType type)
Set the value of this revision.
Definition: vcsrevision.cpp:83
QModelIndex::data
QVariant data(int role) const
QSortFilterProxyModel::setFilterWildcard
void setFilterWildcard(const QString &pattern)
QSortFilterProxyModel
VCSDiffUpdater::vcs
virtual KDevelop::IBasicVersionControl * vcs() const =0
vcsdiffpatchsources.h
QString
KJob
vcsjob.h
QLineEdit::textChanged
void textChanged(const QString &text)
QUrl::fromLocalFile
QUrl fromLocalFile(const QString &localFile)
KDevelop::DistributedVersionControlPlugin
DistributedVersionControlPlugin is a base class for git/hg/bzr plugins.
Definition: dvcsplugin.h:47
QWidget::setWindowTitle
void setWindowTitle(const QString &)
QDialogButtonBox::accepted
void accepted()
QInputDialog::getText
QString getText(QWidget *parent, const QString &title, const QString &label, QLineEdit::EchoMode mode, const QString &text, bool *ok, QFlags< Qt::WindowType > flags, QFlags< Qt::InputMethodHint > inputMethodHints)
QDialog::accept
virtual void accept()
QStandardItem::index
QModelIndex index() const
QList::isEmpty
bool isEmpty() const
BranchManager::BranchManager
BranchManager(const QString &repository, KDevelop::DistributedVersionControlPlugin *executor, QWidget *parent=nullptr)
Definition: branchmanager.cpp:45
branchmanager.h
QModelIndex::isValid
bool isValid() const
KDevelop::VcsRevision::Working
The local copy (including any changes made).
Definition: vcsrevision.h:88
KDevelop::IBranchingVersionControl::mergeBranch
virtual VcsJob * mergeBranch(const QUrl &repository, const QString &branchName)=0
Merges the selected branch into the current one.
QScopedPointer
VCSDiffUpdater
Definition: vcsdiffpatchsources.h:45
KDevelop::VcsJob
This class provides an extension of KJob to get various VCS-specific information about the job.
Definition: vcsjob.h:43
QDialogButtonBox::rejected
void rejected()
KDevelop::BranchesListModel::currentBranch
QString currentBranch
Definition: brancheslistmodel.h:56
KDevelop
Definition: dvcsevent.h:33
KDevelop::VcsJob::JobSucceeded
The job succeeded.
Definition: vcsjob.h:86
QModelIndex
KDevelop::BranchesListModel::removeBranch
Q_INVOKABLE void removeBranch(const QString &branch)
Definition: brancheslistmodel.cpp:141
QDialog
KDevelop::VcsRevision::GlobalNumber
Global repository version when item was last changed.
Definition: vcsrevision.h:79
QDialogButtonBox
brancheslistmodel.h
QVariant::toString
QString toString() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Wed Jan 27 2021 23:31:35 by doxygen 1.8.16 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kdevplatform/vcs

Skip menu "kdevplatform/vcs"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdevelop API Reference

Skip menu "kdevelop API Reference"
  • kdevplatform
  •   debugger
  •   documentation
  •   interfaces
  •   language
  •     assistant
  •     backgroundparser
  •     checks
  •     classmodel
  •     codecompletion
  •     codegen
  •     duchain
  •     editor
  •     highlighting
  •     interfaces
  •     util
  •   outputview
  •   project
  •   serialization
  •   shell
  •   sublime
  •   tests
  •   util
  •   vcs

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal