KTextEditor

kateswapdiffcreator.cpp
1/*
2 SPDX-FileCopyrightText: 2010-2018 Dominik Haumann <dhaumann@kde.org>
3
4 SPDX-License-Identifier: LGPL-2.0-or-later
5*/
6#include "kateswapdiffcreator.h"
7#include "katedocument.h"
8#include "katepartdebug.h"
9#include "kateswapfile.h"
10#include <ktexteditor/view.h>
11
12#include <KIO/JobUiDelegateFactory>
13#include <KIO/OpenUrlJob>
14#include <KLocalizedString>
15#include <KMessageBox>
16
17#include <QDir>
18#include <QStandardPaths>
19
20// BEGIN SwapDiffCreator
21SwapDiffCreator::SwapDiffCreator(Kate::SwapFile *swapFile)
22 : QObject(swapFile)
23 , m_swapFile(swapFile)
24{
25}
26
27void SwapDiffCreator::viewDiff()
28{
29 QString path = m_swapFile->fileName();
30 if (path.isNull()) {
31 return;
32 }
33
34 QFile swp(path);
35 if (!swp.open(QIODevice::ReadOnly)) {
36 qCWarning(LOG_KTE) << "Can't open swap file";
37 return;
38 }
39
40 // create all needed tempfiles
41 m_originalFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.original")));
42 m_recoveredFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.recovered")));
43 m_diffFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.diff")));
44
45 if (!m_originalFile.open() || !m_recoveredFile.open() || !m_diffFile.open()) {
46 qCWarning(LOG_KTE) << "Can't open temporary files needed for diffing";
47 return;
48 }
49
50 // truncate files, just in case
51 m_originalFile.resize(0);
52 m_recoveredFile.resize(0);
53 m_diffFile.resize(0);
54
55 // create a document with the recovered data
56 KTextEditor::DocumentPrivate recoverDoc;
57 recoverDoc.setText(m_swapFile->document()->text());
58
59 // store original text in a file as utf-8 and close it
60 {
61 QTextStream stream(&m_originalFile);
62 stream << recoverDoc.text();
63 }
64 m_originalFile.close();
65
66 // recover data
67 QDataStream stream(&swp);
68 recoverDoc.swapFile()->recover(stream, false);
69
70 // store recovered text in a file as utf-8 and close it
71 {
72 QTextStream stream(&m_recoveredFile);
73 stream << recoverDoc.text();
74 }
75 m_recoveredFile.close();
76
77 // create a process for diff
79
80 connect(&m_proc, &QProcess::readyRead, this, &SwapDiffCreator::slotDataAvailable, Qt::UniqueConnection);
81 connect(&m_proc, &QProcess::finished, this, &SwapDiffCreator::slotDiffFinished, Qt::UniqueConnection);
82
83 // use diff from PATH only => inform if not found at all
84 const QString fullDiffPath = QStandardPaths::findExecutable(QStringLiteral("diff"));
85 if (fullDiffPath.isEmpty()) {
86 KMessageBox::error(m_swapFile->document()->activeView(),
87 i18n("The diff command could not be found. Please make sure that "
88 "diff(1) is installed and in your PATH."),
89 i18n("Error Creating Diff"));
91 return;
92 }
93
94 // try to start the diff program, might fail, too
95 m_proc.start(fullDiffPath, QStringList() << QStringLiteral("-u") << m_originalFile.fileName() << m_recoveredFile.fileName());
96 if (!m_proc.waitForStarted()) {
97 KMessageBox::error(m_swapFile->document()->activeView(),
98 i18n("The diff command '%1' could not be started.").arg(fullDiffPath),
99 i18n("Error Creating Diff"));
100 deleteLater();
101 return;
102 }
103
104 // process is up and running, we can write data to it
105 QTextStream ts(&m_proc);
106 int lineCount = recoverDoc.lines();
107 for (int line = 0; line < lineCount; ++line) {
108 ts << recoverDoc.line(line) << '\n';
109 }
110 ts.flush();
111 m_proc.closeWriteChannel();
112}
113
114void SwapDiffCreator::slotDataAvailable()
115{
116 // collect diff output
117 m_diffFile.write(m_proc.readAll());
118}
119
120void SwapDiffCreator::slotDiffFinished()
121{
122 // collect last diff output, if any
123 m_diffFile.write(m_proc.readAll());
124
125 // get the exit status to check whether diff command run successfully
126 const QProcess::ExitStatus es = m_proc.exitStatus();
127
128 // check exit status
129 if (es != QProcess::NormalExit) {
130 KMessageBox::error(m_swapFile->document()->activeView(),
131 i18n("The diff command failed. Please make sure that "
132 "diff(1) is installed and in your PATH."),
133 i18n("Error Creating Diff"));
134 deleteLater();
135 return;
136 }
137
138 // sanity check: is there any diff content?
139 if (m_diffFile.size() == 0) {
140 KMessageBox::information(m_swapFile->document()->activeView(), i18n("The files are identical."), i18n("Diff Output"));
141 deleteLater();
142 return;
143 }
144
145 // close diffFile and avoid removal, KIO::OpenUrlJob will do that later!
146 m_diffFile.close();
147 m_diffFile.setAutoRemove(false);
148
149 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(m_diffFile.fileName()), QStringLiteral("text/x-patch"));
150 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, m_swapFile->document()->activeView()));
151 job->setDeleteTemporaryFile(true); // delete the file, once the client exits
152 job->start();
153
154 deleteLater();
155}
156
157// END SwapDiffCreator
void setDeleteTemporaryFile(bool b)
void start() override
void setUiDelegate(KJobUiDelegate *delegate)
Class for tracking editing actions.
QString i18n(const char *text, const TYPE &arg...)
KIOCORE_EXPORT KJobUiDelegate * createDefaultJobUiDelegate()
QString path(const QString &relativePath)
void information(QWidget *parent, const QString &text, const QString &title=QString(), const QString &dontShowAgainName=QString(), Options options=Notify)
void error(QWidget *parent, const QString &text, const QString &title, const KGuiItem &buttonOk, Options options=Notify)
QDir temp()
bool resize(const QString &fileName, qint64 sz)
virtual qint64 size() const const override
virtual void close() override
QByteArray readAll()
void readyRead()
qint64 write(const QByteArray &data)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
void deleteLater()
void closeWriteChannel()
QProcess::ExitStatus exitStatus() const const
void finished(int exitCode, QProcess::ExitStatus exitStatus)
void setProcessChannelMode(ProcessChannelMode mode)
void start(OpenMode mode)
bool waitForStarted(int msecs)
QString findExecutable(const QString &executableName, const QStringList &paths)
bool isEmpty() const const
bool isNull() const const
UniqueConnection
virtual QString fileName() const const override
void setAutoRemove(bool b)
void setFileTemplate(const QString &name)
QUrl fromLocalFile(const QString &localFile)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:15:44 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.