• 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
  • widgets
vcsdiffpatchsources.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2009 David Nolden <[email protected]>
3 
4  This library is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License version 2 as published by the Free Software Foundation.
7 
8  This library is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  Library General Public License for more details.
12 
13  You should have received a copy of the GNU Library General Public License
14  along with this library; see the file COPYING.LIB. If not, write to
15  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
16  Boston, MA 02110-1301, USA.
17 */
18 
19 #include "vcsdiffpatchsources.h"
20 
21 #include <QHBoxLayout>
22 #include <QVBoxLayout>
23 #include <QDir>
24 #include <QFontDatabase>
25 #include <QLabel>
26 #include <QTemporaryFile>
27 
28 #include <KComboBox>
29 #include <KConfigGroup>
30 #include <KLocalizedString>
31 #include <KMessageBox>
32 #include <KTextEdit>
33 
34 #include <interfaces/ibasicversioncontrol.h>
35 #include <interfaces/icore.h>
36 #include <interfaces/iprojectcontroller.h>
37 #include <interfaces/iplugincontroller.h>
38 #include <interfaces/iruncontroller.h>
39 #include <interfaces/isession.h>
40 #include "vcsdiff.h"
41 #include "vcsjob.h"
42 #include "debug.h"
43 
44 
45 using namespace KDevelop;
46 
47 VCSCommitDiffPatchSource::VCSCommitDiffPatchSource(VCSDiffUpdater* updater)
48  : VCSDiffPatchSource(updater), m_vcs(updater->vcs())
49 {
50  Q_ASSERT(m_vcs);
51  m_commitMessageWidget = new QWidget;
52  auto* layout = new QVBoxLayout(m_commitMessageWidget.data());
53  layout->setContentsMargins(0, 0, 0, 0);
54 
55  m_commitMessageEdit = new KTextEdit;
56  m_commitMessageEdit.data()->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
57  m_commitMessageEdit.data()->setLineWrapMode(QTextEdit::NoWrap);
58  m_vcs->setupCommitMessageEditor(updater->url(), m_commitMessageEdit.data());
59 
60  auto* titleLayout = new QHBoxLayout;
61  titleLayout->addWidget(new QLabel(i18nc("@label:textbox", "Commit message:")));
62 
63  m_oldMessages = new KComboBox(m_commitMessageWidget.data());
64 
65  m_oldMessages->addItem(i18n("Old Messages"));
66  const auto oldMessages = this->oldMessages();
67  for (const QString& message : oldMessages) {
68  m_oldMessages->addItem(message, message);
69  }
70  m_oldMessages->setMaximumWidth(200);
71 
72  connect(m_oldMessages, &QComboBox::currentTextChanged,
73  this, &VCSCommitDiffPatchSource::oldMessageChanged);
74 
75  titleLayout->addWidget(m_oldMessages);
76 
77  layout->addLayout(titleLayout);
78  layout->addWidget(m_commitMessageEdit.data());
79  connect(this, &VCSCommitDiffPatchSource::reviewCancelled, this, &VCSCommitDiffPatchSource::addMessageToHistory);
80  connect(this, &VCSCommitDiffPatchSource::reviewFinished, this, &VCSCommitDiffPatchSource::addMessageToHistory);
81 }
82 
83 QStringList VCSCommitDiffPatchSource::oldMessages() const
84 {
85  KConfigGroup vcsGroup(ICore::self()->activeSession()->config(), "VCS");
86  return vcsGroup.readEntry("OldCommitMessages", QStringList());
87 }
88 
89 void VCSCommitDiffPatchSource::addMessageToHistory(const QString& message)
90 {
91  if(ICore::self()->shuttingDown())
92  return;
93 
94  KConfigGroup vcsGroup(ICore::self()->activeSession()->config(), "VCS");
95 
96  const int maxMessages = 10;
97  QStringList oldMessages = vcsGroup.readEntry("OldCommitMessages", QStringList());
98 
99  oldMessages.removeAll(message);
100  oldMessages.push_front(message);
101  oldMessages = oldMessages.mid(0, maxMessages);
102 
103  vcsGroup.writeEntry("OldCommitMessages", oldMessages);
104 }
105 
106 void VCSCommitDiffPatchSource::oldMessageChanged(const QString& text)
107 {
108  if(m_oldMessages->currentIndex() != 0)
109  {
110  m_oldMessages->setCurrentIndex(0);
111  m_commitMessageEdit.data()->setText(text);
112  }
113 }
114 
115 void VCSCommitDiffPatchSource::jobFinished(KJob *job)
116 {
117  if (!job || job->error() != 0 )
118  {
119  QString details = job ? job->errorText() : QString();
120  if (details.isEmpty()) { //errorText may be empty
121  details = i18n("For more detailed information please see the Version Control tool view.");
122  }
123  KMessageBox::detailedError(nullptr, i18n("Unable to commit"), details, i18nc("@title:window", "Commit Unsuccessful"));
124  }
125 
126  deleteLater();
127 }
128 
129 VCSDiffPatchSource::VCSDiffPatchSource(VCSDiffUpdater* updater)
130  : m_updater(updater)
131 {
132  update();
133  KDevelop::IBasicVersionControl* vcs = m_updater->vcs();
134  QUrl url = m_updater->url();
135 
136  QScopedPointer<VcsJob> statusJob(vcs->status(QList<QUrl>() << url));
137  QVariant varlist;
138 
139  if( statusJob->exec() && statusJob->status() == VcsJob::JobSucceeded )
140  {
141  varlist = statusJob->fetchResults();
142 
143  const auto vars = varlist.toList();
144  m_infos.reserve(m_infos.size() + vars.size());
145  for (const auto& var : vars) {
146  VcsStatusInfo info = var.value<KDevelop::VcsStatusInfo>();
147 
148  m_infos += info;
149  if(info.state()!=VcsStatusInfo::ItemUpToDate)
150  m_selectable[info.url()] = info.state();
151  }
152  }
153  else
154  qCDebug(VCS) << "Couldn't get status for urls: " << url;
155 }
156 
157 VCSDiffPatchSource::VCSDiffPatchSource(const KDevelop::VcsDiff& diff)
158  : m_updater(nullptr)
159 {
160  updateFromDiff(diff);
161 }
162 
163 VCSDiffPatchSource::~VCSDiffPatchSource()
164 {
165  QFile::remove(m_file.toLocalFile());
166  delete m_updater;
167 }
168 
169 QUrl VCSDiffPatchSource::baseDir() const {
170  return m_base;
171 }
172 
173 QUrl VCSDiffPatchSource::file() const {
174  return m_file;
175 }
176 
177 QString VCSDiffPatchSource::name() const {
178  return m_name;
179 }
180 
181 uint VCSDiffPatchSource::depth() const {
182  return m_depth;
183 }
184 
185 void VCSDiffPatchSource::updateFromDiff(const VcsDiff& vcsdiff)
186 {
187  if(!m_file.isValid())
188  {
189  QTemporaryFile temp2(QDir::tempPath() + QLatin1String("/kdevelop_XXXXXX.patch"));
190  temp2.setAutoRemove(false);
191  temp2.open();
192  QTextStream t2(&temp2);
193  t2 << vcsdiff.diff();
194  qCDebug(VCS) << "filename:" << temp2.fileName();
195  m_file = QUrl::fromLocalFile(temp2.fileName());
196  temp2.close();
197  }else{
198  QFile file(m_file.path());
199  file.open(QIODevice::WriteOnly);
200  QTextStream t2(&file);
201  t2 << vcsdiff.diff();
202  }
203 
204  qCDebug(VCS) << "using file" << m_file << vcsdiff.diff() << "base" << vcsdiff.baseDiff();
205 
206  m_name = QStringLiteral("VCS Diff");
207  m_base = vcsdiff.baseDiff();
208  m_depth = vcsdiff.depth();
209 
210  emit patchChanged();
211 }
212 
213 void VCSDiffPatchSource::update() {
214  if(!m_updater)
215  return;
216  updateFromDiff(m_updater->update());
217 }
218 
219 VCSCommitDiffPatchSource::~VCSCommitDiffPatchSource() {
220  delete m_commitMessageWidget.data();
221 }
222 
223 bool VCSCommitDiffPatchSource::canSelectFiles() const {
224  return true;
225 }
226 
227 QMap< QUrl, KDevelop::VcsStatusInfo::State> VCSDiffPatchSource::additionalSelectableFiles() const {
228  return m_selectable;
229 }
230 
231 QWidget* VCSCommitDiffPatchSource::customWidget() const {
232  return m_commitMessageWidget.data();
233 }
234 
235 QString VCSCommitDiffPatchSource::finishReviewCustomText() const {
236  return i18nc("@action:button To make a commit", "Commit");
237 }
238 
239 bool VCSCommitDiffPatchSource::canCancel() const {
240  return true;
241 }
242 
243 void VCSCommitDiffPatchSource::cancelReview() {
244 
245  QString message;
246 
247  if (m_commitMessageEdit)
248  message = m_commitMessageEdit.data()->toPlainText();
249 
250  emit reviewCancelled(message);
251 
252  deleteLater();
253 }
254 
255 bool VCSCommitDiffPatchSource::finishReview(const QList<QUrl>& selection)
256 {
257  QString message;
258 
259  if (m_commitMessageEdit)
260  message = m_commitMessageEdit.data()->toPlainText();
261 
262  qCDebug(VCS) << "Finishing with selection" << selection;
263  QString files;
264  files.reserve(selection.size());
265  for (const QUrl& url : selection) {
266  files += QLatin1String("<li>") + ICore::self()->projectController()->prettyFileName(url, KDevelop::IProjectController::FormatPlain) + QLatin1String("</li>");
267  }
268 
269  QString text = i18n("<qt>Files will be committed:\n<ul>%1</ul>\nWith message:\n <pre>%2</pre></qt>", files, message);
270 
271  int res = KMessageBox::warningContinueCancel(nullptr, text, i18nc("@title:window", "About to Commit to Repository"),
272  KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
273  QStringLiteral("ShouldAskConfirmCommit"));
274  if (res != KMessageBox::Continue) {
275  return false;
276  }
277 
278  emit reviewFinished(message, selection);
279 
280  VcsJob* job = m_vcs->commit(message, selection, KDevelop::IBasicVersionControl::NonRecursive);
281  if (!job) {
282  return false;
283  }
284 
285  connect (job, &VcsJob::finished,
286  this, &VCSCommitDiffPatchSource::jobFinished);
287  ICore::self()->runController()->registerJob(job);
288  return true;
289 }
290 
291 bool showVcsDiff(IPatchSource* vcsDiff)
292 {
293  auto* patchReview = ICore::self()->pluginController()->extensionForPlugin<IPatchReview>(QStringLiteral("org.kdevelop.IPatchReview"));
294 
295  if( patchReview ) {
296  patchReview->startReview(vcsDiff);
297  return true;
298  } else {
299  qCWarning(VCS) << "Patch review plugin not found";
300  return false;
301  }
302 }
303 
304 VcsDiff VCSStandardDiffUpdater::update() const
305 {
306  QScopedPointer<VcsJob> diffJob(m_vcs->diff(m_url,
307  KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Base),
308  KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Working)));
309  const bool success = diffJob ? diffJob->exec() : false;
310  if (!success) {
311  KMessageBox::error(nullptr, i18n("Could not create a patch for the current version."));
312  return {};
313  }
314 
315  return diffJob->fetchResults().value<VcsDiff>();
316 }
317 
318 VCSStandardDiffUpdater::VCSStandardDiffUpdater(IBasicVersionControl* vcs, const QUrl& url)
319  : m_vcs(vcs)
320  , m_url(url)
321 {
322 }
323 
324 VCSStandardDiffUpdater::~VCSStandardDiffUpdater() {
325 }
326 
327 VCSDiffUpdater::~VCSDiffUpdater() {
328 }
329 
VCSCommitDiffPatchSource::finishReview
bool finishReview(const QList< QUrl > &selection) override
Called when the user has reviewed and accepted this patch If canSelectFiles() returned true,...
Definition: vcsdiffpatchsources.cpp:255
KDevelop::IPatchSource::patchChanged
void patchChanged()
Should be emitted whenever the patch has changed.
QVBoxLayout
VCSDiffPatchSource::depth
uint depth() const override
Depth - number of directories to left-strip from paths in the patch - see "patch -p" Defaults to 0.
Definition: vcsdiffpatchsources.cpp:181
VCSCommitDiffPatchSource::oldMessageChanged
void oldMessageChanged(const QString &)
Definition: vcsdiffpatchsources.cpp:106
VCSDiffUpdater::update
virtual KDevelop::VcsDiff update() const =0
VCSDiffPatchSource::additionalSelectableFiles
QMap< QUrl, KDevelop::VcsStatusInfo::State > additionalSelectableFiles() const override
May return an additional list of selectable files together with short description strings for this pa...
Definition: vcsdiffpatchsources.cpp:227
VCSCommitDiffPatchSource::~VCSCommitDiffPatchSource
~VCSCommitDiffPatchSource() override
Definition: vcsdiffpatchsources.cpp:219
VCSDiffPatchSource::~VCSDiffPatchSource
~VCSDiffPatchSource() override
Definition: vcsdiffpatchsources.cpp:163
QUrl
VCSDiffPatchSource::update
void update() override
Explicit updating of the patch: If it is a dynamic patch, it should re-compare the files or whatever ...
Definition: vcsdiffpatchsources.cpp:213
QList::push_front
void push_front(const T &value)
QFile::remove
bool remove()
VCSDiffPatchSource::VCSDiffPatchSource
VCSDiffPatchSource(VCSDiffUpdater *updater)
The ownership of the updater is taken.
Definition: vcsdiffpatchsources.cpp:129
QList::removeAll
int removeAll(const T &value)
VCSDiffPatchSource::m_name
QString m_name
Definition: vcsdiffpatchsources.h:89
VCSCommitDiffPatchSource::addMessageToHistory
void addMessageToHistory(const QString &message)
Definition: vcsdiffpatchsources.cpp:89
QWidget
VCSDiffPatchSource
Definition: vcsdiffpatchsources.h:66
VCSCommitDiffPatchSource::cancelReview
void cancelReview() override
Called when the user has rejected this patch.
Definition: vcsdiffpatchsources.cpp:243
VCSCommitDiffPatchSource::canSelectFiles
bool canSelectFiles() const override
Should return whether the user should be able to select files of the patch The files available for se...
Definition: vcsdiffpatchsources.cpp:223
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
VCSCommitDiffPatchSource::reviewCancelled
void reviewCancelled(const QString &message)
KDevelop::IBasicVersionControl
This is the basic interface that all Version Control or Source Code Management plugins need to implem...
Definition: ibasicversioncontrol.h:52
KDevelop::VcsRevision::Base
The repository source of the local copy.
Definition: vcsrevision.h:89
showVcsDiff
bool showVcsDiff(IPatchSource *vcsDiff)
Sends the diff to the patch-review plugin.
Definition: vcsdiffpatchsources.cpp:291
ibasicversioncontrol.h
VCSDiffPatchSource::m_file
QUrl m_file
Definition: vcsdiffpatchsources.h:88
KDevelop::IPatchReview::startReview
virtual void startReview(IPatchSource *patch, ReviewMode mode=OpenAndRaise)=0
Starts a review on the patch: Opens the patch and the files within the review area.
KDevelop::VcsStatusInfo::state
VcsStatusInfo::State state() const
Definition: vcsstatusinfo.cpp:108
QString::reserve
void reserve(int size)
VCSCommitDiffPatchSource::oldMessages
QStringList oldMessages() const
Definition: vcsdiffpatchsources.cpp:83
VCSCommitDiffPatchSource::jobFinished
void jobFinished(KJob *)
Definition: vcsdiffpatchsources.cpp:115
VCSDiffUpdater::url
virtual QUrl url() const =0
QList< QUrl >
vcsdiff.h
QObject::connect
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
VCSCommitDiffPatchSource::finishReviewCustomText
QString finishReviewCustomText() const override
May return a custom text for the "Finish Review" action.
Definition: vcsdiffpatchsources.cpp:235
VCSDiffPatchSource::baseDir
QUrl baseDir() const override
Should return the base-dir of the patch.
Definition: vcsdiffpatchsources.cpp:169
QBoxLayout::addWidget
void addWidget(QWidget *widget, int stretch, QFlags< Qt::AlignmentFlag > alignment)
KDevelop::VcsDiff::depth
uint depth() const
Depth - number of directories to left-strip from paths in the patch - see "patch -p" Defaults to 0.
Definition: vcsdiff.cpp:93
QLabel
QDir::tempPath
QString tempPath()
QList::reserve
void reserve(int alloc)
VCSCommitDiffPatchSource::customWidget
QWidget * customWidget() const override
Can return a custom widget that should be shown to the user with this patch The ownership of the widg...
Definition: vcsdiffpatchsources.cpp:231
VCSCommitDiffPatchSource::m_commitMessageEdit
QPointer< KTextEdit > m_commitMessageEdit
Definition: vcsdiffpatchsources.h:124
QUrl::isValid
bool isValid() const
VCSCommitDiffPatchSource::VCSCommitDiffPatchSource
VCSCommitDiffPatchSource(VCSDiffUpdater *updater)
The ownership of the updater is taken.
Definition: vcsdiffpatchsources.cpp:47
QList::size
int size() const
VCSStandardDiffUpdater::update
KDevelop::VcsDiff update() const override
Definition: vcsdiffpatchsources.cpp:304
QObject::deleteLater
void deleteLater()
VCSDiffUpdater::vcs
virtual KDevelop::IBasicVersionControl * vcs() const =0
VCSDiffPatchSource::m_selectable
QMap< QUrl, KDevelop::VcsStatusInfo::State > m_selectable
Definition: vcsdiffpatchsources.h:92
VCSDiffPatchSource::m_updater
VCSDiffUpdater * m_updater
Definition: vcsdiffpatchsources.h:90
VCSCommitDiffPatchSource::canCancel
bool canCancel() const override
Should return whether the user may cancel this review (cancelReview will be called when he does) The ...
Definition: vcsdiffpatchsources.cpp:239
vcsdiffpatchsources.h
QString
KJob
vcsjob.h
QTextStream
VCSDiffPatchSource::name
QString name() const override
Name of the patch, that will be shown in a combo box.
Definition: vcsdiffpatchsources.cpp:177
VCSDiffPatchSource::m_infos
QList< KDevelop::VcsStatusInfo > m_infos
Definition: vcsdiffpatchsources.h:91
QList::mid
QList< T > mid(int pos, int length) const
KDevelop::IPatchSource
Any entity may delete an IPatchSource based object at will, so it must always be referenced through a...
Definition: ipatchsource.h:32
QString::isEmpty
bool isEmpty() const
QUrl::fromLocalFile
QUrl fromLocalFile(const QString &localFile)
VCSCommitDiffPatchSource::m_commitMessageWidget
QPointer< QWidget > m_commitMessageWidget
Definition: vcsdiffpatchsources.h:123
QUrl::toLocalFile
QString toLocalFile() const
VCSDiffPatchSource::file
QUrl file() const override
Name of the patch file.
Definition: vcsdiffpatchsources.cpp:173
QLatin1String
KDevelop::VcsRevision::Working
The local copy (including any changes made).
Definition: vcsrevision.h:88
QScopedPointer
KDevelop::VcsStatusInfo::url
QUrl url() const
retrieves the url of this status information item
Definition: vcsstatusinfo.cpp:103
KDevelop::VcsDiff::diff
QString diff() const
Definition: vcsdiff.cpp:71
QMap< QUrl, KDevelop::VcsStatusInfo::State >
VCSDiffUpdater
Definition: vcsdiffpatchsources.h:45
VCSStandardDiffUpdater::VCSStandardDiffUpdater
VCSStandardDiffUpdater(KDevelop::IBasicVersionControl *vcs, const QUrl &url)
Definition: vcsdiffpatchsources.cpp:318
QUrl::path
QString path() const
KDevelop::VcsJob
This class provides an extension of KJob to get various VCS-specific information about the job.
Definition: vcsjob.h:43
KDevelop::IBasicVersionControl::NonRecursive
don't run recursively through subdirectories
Definition: ibasicversioncontrol.h:59
QHBoxLayout
QLayout::setContentsMargins
void setContentsMargins(int left, int top, int right, int bottom)
KDevelop
Definition: dvcsevent.h:33
VCSDiffPatchSource::m_base
QUrl m_base
Definition: vcsdiffpatchsources.h:88
KDevelop::VcsRevision::createSpecialRevision
static VcsRevision createSpecialRevision(KDevelop::VcsRevision::RevisionSpecialType type)
Helper function to create a vcs revision for one of the special types.
Definition: vcsrevision.cpp:49
KDevelop::VcsDiff::baseDiff
QUrl baseDiff() const
Definition: vcsdiff.cpp:88
KDevelop::IBasicVersionControl::setupCommitMessageEditor
virtual void setupCommitMessageEditor(const QUrl &, KTextEdit *edit) const
Optionally apply VCS specific settings to the commit message editor.
Definition: ibasicversioncontrol.cpp:24
VCSStandardDiffUpdater::~VCSStandardDiffUpdater
~VCSStandardDiffUpdater() override
Definition: vcsdiffpatchsources.cpp:324
KDevelop::VcsStatusInfo
Class that encapsulates status information for one local url.
Definition: vcsstatusinfo.h:47
QPointer::data
T * data() const
QVariant
VCSDiffUpdater::~VCSDiffUpdater
virtual ~VCSDiffUpdater()
Definition: vcsdiffpatchsources.cpp:327
VCSCommitDiffPatchSource::m_vcs
KDevelop::IBasicVersionControl * m_vcs
Definition: vcsdiffpatchsources.h:125
QFile
KDevelop::IBasicVersionControl::commit
virtual VcsJob * commit(const QString &message, const QList< QUrl > &localLocations, RecursionMode recursion=IBasicVersionControl::Recursive)=0
Checks in the changes of the given file(s)/dir(s) into the repository.
VCSCommitDiffPatchSource::m_oldMessages
KComboBox * m_oldMessages
Definition: vcsdiffpatchsources.h:126
QStringList
KDevelop::IPatchReview
Definition: ipatchsource.h:97
VCSCommitDiffPatchSource::reviewFinished
void reviewFinished(const QString &message, const QList< QUrl > &selection)
KDevelop::IBasicVersionControl::status
virtual VcsJob * status(const QList< QUrl > &localLocations, RecursionMode recursion=IBasicVersionControl::Recursive)=0
Fetches the status of the given local vcs locations.
QTemporaryFile
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Jan 25 2021 23:37:48 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