vcsdiffpatchsources.cpp 9.74 KB
Newer Older
1
2
/*
    Copyright 2009 David Nolden <david.nolden.kdevelop@art-master.de>
Dāvis Mosāns's avatar
Dāvis Mosāns committed
3

4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Library General Public
   License version 2 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   Library General Public License for more details.

   You should have received a copy of the GNU Library General Public License
   along with this library; see the file COPYING.LIB.  If not, write to
   the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
   Boston, MA 02110-1301, USA.
*/

#include "vcsdiffpatchsources.h"
20

21
22
#include <QHBoxLayout>
#include <QVBoxLayout>
23
#include <QDir>
24
#include <QFontDatabase>
25
26
27
28
#include <QLabel>
#include <QTemporaryFile>

#include <KComboBox>
Kevin Funk's avatar
Kevin Funk committed
29
#include <KConfigGroup>
30
31
32
33
34
#include <KLocalizedString>
#include <KMessageBox>
#include <KTextEdit>

#include <interfaces/ibasicversioncontrol.h>
35
#include <interfaces/icore.h>
36
37
#include <interfaces/iprojectcontroller.h>
#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
46
using namespace KDevelop;

47
48
VCSCommitDiffPatchSource::VCSCommitDiffPatchSource(VCSDiffUpdater* updater)
    : VCSDiffPatchSource(updater), m_vcs(updater->vcs())
49
{
50
51
    Q_ASSERT(m_vcs);
    m_commitMessageWidget = new QWidget;
52
    auto* layout = new QVBoxLayout(m_commitMessageWidget.data());
53
    layout->setMargin(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());
Dāvis Mosāns's avatar
Dāvis Mosāns committed
59

60
    auto* titleLayout = new QHBoxLayout;
61
    titleLayout->addWidget(new QLabel(i18n("Commit Message:")));
Dāvis Mosāns's avatar
Dāvis Mosāns committed
62

63
    m_oldMessages = new KComboBox(m_commitMessageWidget.data());
Dāvis Mosāns's avatar
Dāvis Mosāns committed
64

65
    m_oldMessages->addItem(i18n("Old Messages"));
66
67
    const auto oldMessages = this->oldMessages();
    for (const QString& message : oldMessages) {
68
        m_oldMessages->addItem(message, message);
69
    }
70
    m_oldMessages->setMaximumWidth(200);
Dāvis Mosāns's avatar
Dāvis Mosāns committed
71

72
    connect(m_oldMessages, &QComboBox::currentTextChanged,
Friedrich W. H. Kossebau's avatar
Friedrich W. H. Kossebau committed
73
            this, &VCSCommitDiffPatchSource::oldMessageChanged);
Dāvis Mosāns's avatar
Dāvis Mosāns committed
74

75
    titleLayout->addWidget(m_oldMessages);
Dāvis Mosāns's avatar
Dāvis Mosāns committed
76

77
    layout->addLayout(titleLayout);
78
    layout->addWidget(m_commitMessageEdit.data());
79
80
    connect(this, &VCSCommitDiffPatchSource::reviewCancelled, this, &VCSCommitDiffPatchSource::addMessageToHistory);
    connect(this, &VCSCommitDiffPatchSource::reviewFinished, this, &VCSCommitDiffPatchSource::addMessageToHistory);
81
82
}

83
84
85
86
87
88
QStringList VCSCommitDiffPatchSource::oldMessages() const
{
    KConfigGroup vcsGroup(ICore::self()->activeSession()->config(), "VCS");
    return vcsGroup.readEntry("OldCommitMessages", QStringList());
}

89
90
91
92
void VCSCommitDiffPatchSource::addMessageToHistory(const QString& message)
{
    if(ICore::self()->shuttingDown())
        return;
Dāvis Mosāns's avatar
Dāvis Mosāns committed
93

94
    KConfigGroup vcsGroup(ICore::self()->activeSession()->config(), "VCS");
Dāvis Mosāns's avatar
Dāvis Mosāns committed
95

96
97
    const int maxMessages = 10;
    QStringList oldMessages = vcsGroup.readEntry("OldCommitMessages", QStringList());
Dāvis Mosāns's avatar
Dāvis Mosāns committed
98

99
100
101
    oldMessages.removeAll(message);
    oldMessages.push_front(message);
    oldMessages = oldMessages.mid(0, maxMessages);
Dāvis Mosāns's avatar
Dāvis Mosāns committed
102

103
104
105
    vcsGroup.writeEntry("OldCommitMessages", oldMessages);
}

106
void VCSCommitDiffPatchSource::oldMessageChanged(const QString& text)
107
108
109
110
{
    if(m_oldMessages->currentIndex() != 0)
    {
        m_oldMessages->setCurrentIndex(0);
111
        m_commitMessageEdit.data()->setText(text);
112
113
114
    }
}

115
116
117
118
119
120
void VCSCommitDiffPatchSource::jobFinished(KJob *job)
{
    if (!job || job->error() != 0 )
    {
        QString details = job ? job->errorText() : QString();
        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, i18n("Commit unsuccessful"));
124
125
126
127
128
    }

    deleteLater();
}

129
130
VCSDiffPatchSource::VCSDiffPatchSource(VCSDiffUpdater* updater)
    : m_updater(updater)
131
{
132
    update();
133
    KDevelop::IBasicVersionControl* vcs = m_updater->vcs();
Milian Wolff's avatar
Milian Wolff committed
134
    QUrl url = m_updater->url();
135

Milian Wolff's avatar
Milian Wolff committed
136
    QScopedPointer<VcsJob> statusJob(vcs->status(QList<QUrl>() << url));
137
138
139
140
141
142
    QVariant varlist;

    if( statusJob->exec() && statusJob->status() == VcsJob::JobSucceeded )
    {
        varlist = statusJob->fetchResults();

143
144
145
        const auto vars = varlist.toList();
        m_infos.reserve(m_infos.size() + vars.size());
        for (const auto& var : vars) {
146
            VcsStatusInfo info = var.value<KDevelop::VcsStatusInfo>();
Dāvis Mosāns's avatar
Dāvis Mosāns committed
147

148
149
150
151
152
153
            m_infos += info;
            if(info.state()!=VcsStatusInfo::ItemUpToDate)
                m_selectable[info.url()] = info.state();
        }
    }
    else
Dāvis Mosāns's avatar
Dāvis Mosāns committed
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
}

Milian Wolff's avatar
Milian Wolff committed
163
164
165
VCSDiffPatchSource::~VCSDiffPatchSource()
{
    QFile::remove(m_file.toLocalFile());
166
    delete m_updater;
Milian Wolff's avatar
Milian Wolff committed
167
168
}

Milian Wolff's avatar
Milian Wolff committed
169
QUrl VCSDiffPatchSource::baseDir() const {
170
171
172
    return m_base;
}

Milian Wolff's avatar
Milian Wolff committed
173
QUrl VCSDiffPatchSource::file() const {
174
175
176
177
178
179
180
    return m_file;
}

QString VCSDiffPatchSource::name() const {
    return m_name;
}

181
182
183
184
uint VCSDiffPatchSource::depth() const {
    return m_depth;
}

185
void VCSDiffPatchSource::updateFromDiff(const VcsDiff& vcsdiff)
186
187
188
{
    if(!m_file.isValid())
    {
189
        QTemporaryFile temp2(QDir::tempPath() + QLatin1String("/kdevelop_XXXXXX.patch"));
190
191
192
193
        temp2.setAutoRemove(false);
        temp2.open();
        QTextStream t2(&temp2);
        t2 << vcsdiff.diff();
Dāvis Mosāns's avatar
Dāvis Mosāns committed
194
        qCDebug(VCS) << "filename:" << temp2.fileName();
Milian Wolff's avatar
Milian Wolff committed
195
        m_file = QUrl::fromLocalFile(temp2.fileName());
196
197
198
199
200
201
202
203
        temp2.close();
    }else{
        QFile file(m_file.path());
        file.open(QIODevice::WriteOnly);
        QTextStream t2(&file);
        t2 << vcsdiff.diff();
    }

Dāvis Mosāns's avatar
Dāvis Mosāns committed
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();
Dāvis Mosāns's avatar
Dāvis Mosāns committed
209

210
211
212
    emit patchChanged();
}

213
void VCSDiffPatchSource::update() {
214
215
216
    if(!m_updater)
        return;
    updateFromDiff(m_updater->update());
217
218
219
}

VCSCommitDiffPatchSource::~VCSCommitDiffPatchSource() {
220
    delete m_commitMessageWidget.data();
221
222
223
224
225
226
}

bool VCSCommitDiffPatchSource::canSelectFiles() const {
    return true;
}

Milian Wolff's avatar
Milian Wolff committed
227
QMap< QUrl, KDevelop::VcsStatusInfo::State> VCSDiffPatchSource::additionalSelectableFiles() const {
228
229
230
231
    return m_selectable;
}

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
240
241
242
243
}

bool VCSCommitDiffPatchSource::canCancel() const {
    return true;
}

void VCSCommitDiffPatchSource::cancelReview() {
Dāvis Mosāns's avatar
Dāvis Mosāns committed
244

245
246
247
    QString message;

    if (m_commitMessageEdit)
248
        message = m_commitMessageEdit.data()->toPlainText();
249
250

    emit reviewCancelled(message);
Dāvis Mosāns's avatar
Dāvis Mosāns committed
251

252
253
254
    deleteLater();
}

255
256
bool VCSCommitDiffPatchSource::finishReview(const QList<QUrl>& selection)
{
257
258
259
    QString message;

    if (m_commitMessageEdit)
260
        message = m_commitMessageEdit.data()->toPlainText();
261

Dāvis Mosāns's avatar
Dāvis Mosāns committed
262
    qCDebug(VCS) << "Finishing with selection" << selection;
263
    QString files;
264
265
    files.reserve(selection.size());
    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, i18n("About to commit to repository"),
272
                                                 KStandardGuiItem::cont(), KStandardGuiItem::cancel(),
273
                                                 QStringLiteral("ShouldAskConfirmCommit"));
274
275
276
277
278
    if (res != KMessageBox::Continue) {
        return false;
    }

    emit reviewFinished(message, selection);
279

280
281
282
283
    VcsJob* job = m_vcs->commit(message, selection, KDevelop::IBasicVersionControl::NonRecursive);
    if (!job) {
        return false;
    }
284

285
286
    connect (job, &VcsJob::finished,
             this, &VCSCommitDiffPatchSource::jobFinished);
287
    ICore::self()->runController()->registerJob(job);
288
289
290
291
292
    return true;
}

bool showVcsDiff(IPatchSource* vcsDiff)
{
293
    auto* patchReview = ICore::self()->pluginController()->extensionForPlugin<IPatchReview>(QStringLiteral("org.kdevelop.IPatchReview"));
294
295

    if( patchReview ) {
296
        patchReview->startReview(vcsDiff);
297
298
        return true;
    } else {
Kevin Funk's avatar
Kevin Funk committed
299
        qCWarning(VCS) << "Patch review plugin not found";
300
301
        return false;
    }
302
303
}

304
305
VcsDiff VCSStandardDiffUpdater::update() const
{
306
307
308
    QScopedPointer<VcsJob> diffJob(m_vcs->diff(m_url,
                                   KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Base),
                                   KDevelop::VcsRevision::createSpecialRevision(KDevelop::VcsRevision::Working)));
309
310
    const bool success = diffJob ? diffJob->exec() : false;
    if (!success) {
311
        KMessageBox::error(nullptr, i18n("Could not create a patch for the current version."));
312
313
        return {};
    }
314

315
    return diffJob->fetchResults().value<VcsDiff>();
316
}
317

318
319
320
321
VCSStandardDiffUpdater::VCSStandardDiffUpdater(IBasicVersionControl* vcs, const QUrl& url)
    : m_vcs(vcs)
    , m_url(url)
{
322
323
}

324
325
326
327
328
329
VCSStandardDiffUpdater::~VCSStandardDiffUpdater() {
}

VCSDiffUpdater::~VCSDiffUpdater() {
}