File indexing completed on 2024-04-28 15:30:46
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 0011 #include <KIO/JobUiDelegateFactory> 0012 #include <KIO/OpenUrlJob> 0013 #include <KLocalizedString> 0014 #include <KMessageBox> 0015 0016 #include <QDir> 0017 #include <QStandardPaths> 0018 #include <QTextCodec> 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.setCodec(QTextCodec::codecForName("UTF-8")); 0063 stream << recoverDoc.text(); 0064 } 0065 m_originalFile.close(); 0066 0067 // recover data 0068 QDataStream stream(&swp); 0069 recoverDoc.swapFile()->recover(stream, false); 0070 0071 // store recovered text in a file as utf-8 and close it 0072 { 0073 QTextStream stream(&m_recoveredFile); 0074 stream.setCodec(QTextCodec::codecForName("UTF-8")); 0075 stream << recoverDoc.text(); 0076 } 0077 m_recoveredFile.close(); 0078 0079 // create a process for diff 0080 m_proc.setProcessChannelMode(QProcess::MergedChannels); 0081 0082 connect(&m_proc, &QProcess::readyRead, this, &SwapDiffCreator::slotDataAvailable, Qt::UniqueConnection); 0083 connect(&m_proc, &QProcess::finished, this, &SwapDiffCreator::slotDiffFinished, Qt::UniqueConnection); 0084 0085 // use diff from PATH only => inform if not found at all 0086 const QString fullDiffPath = QStandardPaths::findExecutable(QStringLiteral("diff")); 0087 if (fullDiffPath.isEmpty()) { 0088 KMessageBox::error(m_swapFile->document()->activeView(), 0089 i18n("The diff command could not be found. Please make sure that " 0090 "diff(1) is installed and in your PATH."), 0091 i18n("Error Creating Diff")); 0092 deleteLater(); 0093 return; 0094 } 0095 0096 // try to start the diff program, might fail, too 0097 m_proc.start(fullDiffPath, QStringList() << QStringLiteral("-u") << m_originalFile.fileName() << m_recoveredFile.fileName()); 0098 if (!m_proc.waitForStarted()) { 0099 KMessageBox::error(m_swapFile->document()->activeView(), 0100 i18n("The diff command '%1' could not be started.").arg(fullDiffPath), 0101 i18n("Error Creating Diff")); 0102 deleteLater(); 0103 return; 0104 } 0105 0106 // process is up and running, we can write data to it 0107 QTextStream ts(&m_proc); 0108 int lineCount = recoverDoc.lines(); 0109 for (int line = 0; line < lineCount; ++line) { 0110 ts << recoverDoc.line(line) << '\n'; 0111 } 0112 ts.flush(); 0113 m_proc.closeWriteChannel(); 0114 } 0115 0116 void SwapDiffCreator::slotDataAvailable() 0117 { 0118 // collect diff output 0119 m_diffFile.write(m_proc.readAll()); 0120 } 0121 0122 void SwapDiffCreator::slotDiffFinished() 0123 { 0124 // collect last diff output, if any 0125 m_diffFile.write(m_proc.readAll()); 0126 0127 // get the exit status to check whether diff command run successfully 0128 const QProcess::ExitStatus es = m_proc.exitStatus(); 0129 0130 // check exit status 0131 if (es != QProcess::NormalExit) { 0132 KMessageBox::error(m_swapFile->document()->activeView(), 0133 i18n("The diff command failed. Please make sure that " 0134 "diff(1) is installed and in your PATH."), 0135 i18n("Error Creating Diff")); 0136 deleteLater(); 0137 return; 0138 } 0139 0140 // sanity check: is there any diff content? 0141 if (m_diffFile.size() == 0) { 0142 KMessageBox::information(m_swapFile->document()->activeView(), i18n("The files are identical."), i18n("Diff Output")); 0143 deleteLater(); 0144 return; 0145 } 0146 0147 // close diffFile and avoid removal, KIO::OpenUrlJob will do that later! 0148 m_diffFile.close(); 0149 m_diffFile.setAutoRemove(false); 0150 0151 KIO::OpenUrlJob *job = new KIO::OpenUrlJob(QUrl::fromLocalFile(m_diffFile.fileName()), QStringLiteral("text/x-patch")); 0152 job->setUiDelegate(KIO::createDefaultJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled, m_swapFile->document()->activeView())); 0153 job->setDeleteTemporaryFile(true); // delete the file, once the client exits 0154 job->start(); 0155 0156 deleteLater(); 0157 } 0158 0159 // END SwapDiffCreator 0160 0161 #include "moc_kateswapdiffcreator.cpp"