File indexing completed on 2024-04-14 03:55:24
0001 /* 0002 SPDX-FileCopyrightText: 2010-2018 Dominik Haumann <dhaumann@kde.org> 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 #include "kateswapdiffcreator.h" 0007 #include "katedocument.h" 0008 #include "katepartdebug.h" 0009 #include "kateswapfile.h" 0010 #include <ktexteditor/view.h> 0011 0012 #include <KIO/JobUiDelegateFactory> 0013 #include <KIO/OpenUrlJob> 0014 #include <KLocalizedString> 0015 #include <KMessageBox> 0016 0017 #include <QDir> 0018 #include <QStandardPaths> 0019 0020 // BEGIN SwapDiffCreator 0021 SwapDiffCreator::SwapDiffCreator(Kate::SwapFile *swapFile) 0022 : QObject(swapFile) 0023 , m_swapFile(swapFile) 0024 { 0025 } 0026 0027 void SwapDiffCreator::viewDiff() 0028 { 0029 QString path = m_swapFile->fileName(); 0030 if (path.isNull()) { 0031 return; 0032 } 0033 0034 QFile swp(path); 0035 if (!swp.open(QIODevice::ReadOnly)) { 0036 qCWarning(LOG_KTE) << "Can't open swap file"; 0037 return; 0038 } 0039 0040 // create all needed tempfiles 0041 m_originalFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.original"))); 0042 m_recoveredFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.recovered"))); 0043 m_diffFile.setFileTemplate(QDir::temp().filePath(QStringLiteral("katepart_XXXXXX.diff"))); 0044 0045 if (!m_originalFile.open() || !m_recoveredFile.open() || !m_diffFile.open()) { 0046 qCWarning(LOG_KTE) << "Can't open temporary files needed for diffing"; 0047 return; 0048 } 0049 0050 // truncate files, just in case 0051 m_originalFile.resize(0); 0052 m_recoveredFile.resize(0); 0053 m_diffFile.resize(0); 0054 0055 // create a document with the recovered data 0056 KTextEditor::DocumentPrivate recoverDoc; 0057 recoverDoc.setText(m_swapFile->document()->text()); 0058 0059 // store original text in a file as utf-8 and close it 0060 { 0061 QTextStream stream(&m_originalFile); 0062 stream << recoverDoc.text(); 0063 } 0064 m_originalFile.close(); 0065 0066 // recover data 0067 QDataStream stream(&swp); 0068 recoverDoc.swapFile()->recover(stream, false); 0069 0070 // store recovered text in a file as utf-8 and close it 0071 { 0072 QTextStream stream(&m_recoveredFile); 0073 stream << recoverDoc.text(); 0074 } 0075 m_recoveredFile.close(); 0076 0077 // create a process for diff 0078 m_proc.setProcessChannelMode(QProcess::MergedChannels); 0079 0080 connect(&m_proc, &QProcess::readyRead, this, &SwapDiffCreator::slotDataAvailable, Qt::UniqueConnection); 0081 connect(&m_proc, &QProcess::finished, this, &SwapDiffCreator::slotDiffFinished, Qt::UniqueConnection); 0082 0083 // use diff from PATH only => inform if not found at all 0084 const QString fullDiffPath = QStandardPaths::findExecutable(QStringLiteral("diff")); 0085 if (fullDiffPath.isEmpty()) { 0086 KMessageBox::error(m_swapFile->document()->activeView(), 0087 i18n("The diff command could not be found. Please make sure that " 0088 "diff(1) is installed and in your PATH."), 0089 i18n("Error Creating Diff")); 0090 deleteLater(); 0091 return; 0092 } 0093 0094 // try to start the diff program, might fail, too 0095 m_proc.start(fullDiffPath, QStringList() << QStringLiteral("-u") << m_originalFile.fileName() << m_recoveredFile.fileName()); 0096 if (!m_proc.waitForStarted()) { 0097 KMessageBox::error(m_swapFile->document()->activeView(), 0098 i18n("The diff command '%1' could not be started.").arg(fullDiffPath), 0099 i18n("Error Creating Diff")); 0100 deleteLater(); 0101 return; 0102 } 0103 0104 // process is up and running, we can write data to it 0105 QTextStream ts(&m_proc); 0106 int lineCount = recoverDoc.lines(); 0107 for (int line = 0; line < lineCount; ++line) { 0108 ts << recoverDoc.line(line) << '\n'; 0109 } 0110 ts.flush(); 0111 m_proc.closeWriteChannel(); 0112 } 0113 0114 void SwapDiffCreator::slotDataAvailable() 0115 { 0116 // collect diff output 0117 m_diffFile.write(m_proc.readAll()); 0118 } 0119 0120 void SwapDiffCreator::slotDiffFinished() 0121 { 0122 // collect last diff output, if any 0123 m_diffFile.write(m_proc.readAll()); 0124 0125 // get the exit status to check whether diff command run successfully 0126 const QProcess::ExitStatus es = m_proc.exitStatus(); 0127 0128 // check exit status 0129 if (es != QProcess::NormalExit) { 0130 KMessageBox::error(m_swapFile->document()->activeView(), 0131 i18n("The diff command failed. Please make sure that " 0132 "diff(1) is installed and in your PATH."), 0133 i18n("Error Creating Diff")); 0134 deleteLater(); 0135 return; 0136 } 0137 0138 // sanity check: is there any diff content? 0139 if (m_diffFile.size() == 0) { 0140 KMessageBox::information(m_swapFile->document()->activeView(), i18n("The files are identical."), i18n("Diff Output")); 0141 deleteLater(); 0142 return; 0143 } 0144 0145 // close diffFile and avoid removal, KIO::OpenUrlJob will do that later! 0146 m_diffFile.close(); 0147 m_diffFile.setAutoRemove(false); 0148 0149 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(m_diffFile.fileName()), QStringLiteral("text/x-patch")); 0150 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, m_swapFile->document()->activeView())); 0151 job->setDeleteTemporaryFile(true); // delete the file, once the client exits 0152 job->start(); 0153 0154 deleteLater(); 0155 } 0156 0157 // END SwapDiffCreator