10#include <komparediffdebug.h>
11#include "difference.h"
12#include "levenshteintable.h"
13#include "stringlistpair.h"
14#include "parserbase.h"
19DiffModel::DiffModel(
const QString& source,
const QString& destination) :
21 m_destination(destination),
27 m_destinationTimestamp(),
29 m_destinationRevision(),
32 m_selectedDifference(nullptr),
35 splitSourceInPathAndFileName();
36 splitDestinationInPathAndFileName();
39DiffModel::DiffModel() :
47 m_destinationTimestamp(),
49 m_destinationRevision(),
52 m_selectedDifference(nullptr),
58DiffModel::~DiffModel()
60 m_selectedDifference =
nullptr;
63 qDeleteAll(m_differences);
66void DiffModel::splitSourceInPathAndFileName()
71 m_sourcePath = m_source.
mid(0, pos + 1);
74 m_sourceFile = m_source.
mid(pos + 1, m_source.
length() - pos);
76 m_sourceFile = m_source;
78 qCDebug(LIBKOMPAREDIFF2) << m_source <<
" was split into " << m_sourcePath <<
" and " << m_sourceFile;
81void DiffModel::splitDestinationInPathAndFileName()
86 m_destinationPath = m_destination.
mid(0, pos + 1);
89 m_destinationFile = m_destination.
mid(pos + 1, m_destination.
length() - pos);
91 m_destinationFile = m_destination;
93 qCDebug(LIBKOMPAREDIFF2) << m_destination <<
" was split into " << m_destinationPath <<
" and " << m_destinationFile;
100 m_source = model.m_source;
101 m_destination = model.m_destination;
102 m_sourcePath = model.m_sourcePath;
103 m_sourceFile = model.m_sourceFile;
104 m_sourceTimestamp = model.m_sourceTimestamp;
105 m_sourceRevision = model.m_sourceRevision;
106 m_destinationPath = model.m_destinationPath;
107 m_destinationFile = model.m_destinationFile;
108 m_destinationTimestamp = model.m_destinationTimestamp;
109 m_destinationRevision = model.m_destinationRevision;
110 m_appliedCount = model.m_appliedCount;
112 m_diffIndex = model.m_diffIndex;
113 m_selectedDifference = model.m_selectedDifference;
119bool DiffModel::operator<(
const DiffModel& model)
121 if (localeAwareCompareSource(model) < 0)
126int DiffModel::localeAwareCompareSource(
const DiffModel& model)
128 qCDebug(LIBKOMPAREDIFF2) <<
"Path: " << model.m_sourcePath;
129 qCDebug(LIBKOMPAREDIFF2) <<
"File: " << model.m_sourceFile;
139QString DiffModel::recreateDiff()
const
147 diff += QStringLiteral(
"--- %1\t%2").
arg(ParserBase::escapePath(m_source), m_sourceTimestamp);
148 if (!m_sourceRevision.
isEmpty())
149 diff += tab + m_sourceRevision;
151 diff += QStringLiteral(
"+++ %1\t%2").
arg(ParserBase::escapePath(m_destination), m_destinationTimestamp);
152 if (!m_destinationRevision.
isEmpty())
153 diff += tab + m_destinationRevision;
157 DiffHunkListConstIterator hunkIt = m_hunks.
begin();
158 DiffHunkListConstIterator hEnd = m_hunks.
end();
160 for (; hunkIt != hEnd; ++hunkIt)
162 if ((*hunkIt)->type() != DiffHunk::AddedByBlend)
163 diff += (*hunkIt)->recreateHunk();
171 qCDebug(LIBKOMPAREDIFF2) <<
"DiffModel::firstDifference()";
173 qCDebug(LIBKOMPAREDIFF2) <<
"m_diffIndex = " << m_diffIndex;
175 m_selectedDifference = m_differences[ m_diffIndex ];
177 return m_selectedDifference;
182 qCDebug(LIBKOMPAREDIFF2) <<
"DiffModel::lastDifference()";
183 m_diffIndex = m_differences.
count() - 1;
184 qCDebug(LIBKOMPAREDIFF2) <<
"m_diffIndex = " << m_diffIndex;
186 m_selectedDifference = m_differences[ m_diffIndex ];
188 return m_selectedDifference;
193 qCDebug(LIBKOMPAREDIFF2) <<
"DiffModel::prevDifference()";
194 if (m_diffIndex > 0 && --m_diffIndex < m_differences.
count())
196 qCDebug(LIBKOMPAREDIFF2) <<
"m_diffIndex = " << m_diffIndex;
197 m_selectedDifference = m_differences[ m_diffIndex ];
201 m_selectedDifference =
nullptr;
203 qCDebug(LIBKOMPAREDIFF2) <<
"m_diffIndex = " << m_diffIndex;
206 return m_selectedDifference;
211 qCDebug(LIBKOMPAREDIFF2) <<
"DiffModel::nextDifference()";
212 if (++m_diffIndex < m_differences.
count())
214 qCDebug(LIBKOMPAREDIFF2) <<
"m_diffIndex = " << m_diffIndex;
215 m_selectedDifference = m_differences[ m_diffIndex ];
219 m_selectedDifference =
nullptr;
221 qCDebug(LIBKOMPAREDIFF2) <<
"m_diffIndex = " << m_diffIndex;
224 return m_selectedDifference;
227const QString DiffModel::sourceFile()
const
232const QString DiffModel::destinationFile()
const
234 return m_destinationFile;
237const QString DiffModel::sourcePath()
const
242const QString DiffModel::destinationPath()
const
244 return m_destinationPath;
247void DiffModel::setSourceFile(
QString path)
250 splitSourceInPathAndFileName();
253void DiffModel::setDestinationFile(
QString path)
255 m_destination =
path;
256 splitDestinationInPathAndFileName();
259void DiffModel::setSourceTimestamp(
QString timestamp)
261 m_sourceTimestamp = timestamp;
264void DiffModel::setDestinationTimestamp(
QString timestamp)
266 m_destinationTimestamp = timestamp;
269void DiffModel::setSourceRevision(
QString revision)
271 m_sourceRevision = revision;
274void DiffModel::setDestinationRevision(
QString revision)
276 m_destinationRevision = revision;
279void DiffModel::addHunk(
DiffHunk* hunk)
286 m_differences.
append(diff);
287 connect(diff, &Difference::differenceApplied,
288 this, &DiffModel::slotDifferenceApplied);
291bool DiffModel::hasUnsavedChanges(
void)
const
293 DifferenceListConstIterator diffIt = m_differences.
begin();
294 DifferenceListConstIterator endIt = m_differences.
end();
296 for (; diffIt != endIt; ++diffIt)
298 if ((*diffIt)->isUnsaved())
305void DiffModel::applyDifference(
bool apply)
307 bool appliedState = m_selectedDifference->applied();
308 if (appliedState == apply)
312 if (apply && !m_selectedDifference->applied())
314 else if (!apply && m_selectedDifference->applied())
317 m_selectedDifference->apply(apply);
320static int GetDifferenceDelta(
Difference* diff)
322 int delta = diff->destinationLineCount() - diff->sourceLineCount();
323 if (!diff->applied())
330void DiffModel::slotDifferenceApplied(
Difference* diff)
332 int delta = GetDifferenceDelta(diff);
334 if (current->destinationLineNumber() > diff->destinationLineNumber())
336 current->setTrackingDestinationLineNumber(current->trackingDestinationLineNumber() + delta);
341void DiffModel::applyAllDifferences(
bool apply)
345 m_appliedCount = m_differences.
count();
352 DifferenceListIterator diffIt = m_differences.
begin();
353 DifferenceListIterator dEnd = m_differences.
end();
356 for (; diffIt != dEnd; ++diffIt)
358 (*diffIt)->setTrackingDestinationLineNumber((*diffIt)->trackingDestinationLineNumber() + totalDelta);
359 bool appliedState = (*diffIt)->applied();
360 if (appliedState == apply)
364 (*diffIt)->applyQuietly(apply);
365 int currentDelta = GetDifferenceDelta(*diffIt);
366 totalDelta += currentDelta;
370bool DiffModel::setSelectedDifference(
Difference* diff)
372 qCDebug(LIBKOMPAREDIFF2) <<
"diff = " << diff;
373 qCDebug(LIBKOMPAREDIFF2) <<
"m_selectedDifference = " << m_selectedDifference;
375 if (diff != m_selectedDifference)
377 if ((m_differences.
indexOf(diff)) == -1)
380 m_diffIndex = m_differences.
indexOf(diff);
381 qCDebug(LIBKOMPAREDIFF2) <<
"m_diffIndex = " << m_diffIndex;
382 m_selectedDifference = diff;
393 if (oldLines.
size() == 0 && newLines.
size() == 0) {
396 int editLineEnd = editLineNumber + oldLines.
size();
400 DifferenceListIterator iterBegin;
401 for (iterBegin = m_differences.
begin(); iterBegin != m_differences.
end(); ++iterBegin) {
404 int lineAfterLast = (*iterBegin)->trackingDestinationLineEnd();
405 if (lineAfterLast > editLineNumber || (lineAfterLast == editLineNumber &&
406 ((*iterBegin)->applied() || (*iterBegin)->trackingDestinationLineNumber() == editLineNumber))) {
410 DifferenceListIterator iterEnd;
411 for (iterEnd = iterBegin; iterEnd != m_differences.
end(); ++iterEnd) {
413 int firstLine = (*iterEnd)->trackingDestinationLineNumber();
414 if (firstLine > editLineEnd || (!(*iterEnd)->applied() && firstLine == editLineEnd)) {
417 if ((*iterEnd)->applied()) {
423 int sourceLineNumber;
424 int destinationLineNumber;
425 if (iterBegin == m_differences.
end()) {
426 destinationLineNumber = editLineNumber;
427 if (!m_differences.
isEmpty()) {
428 sourceLineNumber = m_differences.
last()->sourceLineEnd() - (m_differences.
last()->trackingDestinationLineEnd() - editLineNumber);
430 sourceLineNumber = destinationLineNumber;
432 }
else if (!(*iterBegin)->applied() || (*iterBegin)->trackingDestinationLineNumber() >= editLineNumber) {
433 destinationLineNumber = editLineNumber;
434 sourceLineNumber = (*iterBegin)->sourceLineNumber() - ((*iterBegin)->trackingDestinationLineNumber() - editLineNumber);
436 sourceLineNumber = (*iterBegin)->sourceLineNumber();
437 destinationLineNumber = (*iterBegin)->trackingDestinationLineNumber();
441 DifferenceListConstIterator appliedBegin = applied.
constBegin();
442 DifferenceListConstIterator appliedEnd = applied.
constEnd();
447 DifferenceListIterator insertPosition;
448 if (appliedBegin == appliedEnd) {
449 destinationLines = newLines;
450 sourceLines = oldLines;
453 int firstDestinationLineNumber = (*appliedBegin)->trackingDestinationLineNumber();
454 for (
int lineNumber = firstDestinationLineNumber; lineNumber < editLineNumber; ++lineNumber) {
455 destinationLines.
append((*appliedBegin)->destinationLineAt(lineNumber - firstDestinationLineNumber)->string());
457 for (
const QString& line : newLines) {
458 destinationLines.
append(line);
460 DifferenceListConstIterator appliedLast = appliedEnd;
462 int lastDestinationLineNumber = (*appliedLast)->trackingDestinationLineNumber();
463 for (
int lineNumber = editLineEnd; lineNumber < (*appliedLast)->trackingDestinationLineEnd(); ++lineNumber) {
464 destinationLines.
append((*appliedLast)->destinationLineAt(lineNumber - lastDestinationLineNumber)->string());
468 if ((*appliedBegin)->trackingDestinationLineNumber() >= editLineNumber) {
469 for (
int i = editLineNumber; i < (*appliedBegin)->trackingDestinationLineNumber(); ++i) {
470 sourceLines.
append(oldLines.
at(i - editLineNumber));
474 for (DifferenceListConstIterator iter = appliedBegin; iter != appliedEnd;) {
475 int startPos = (*iter)->trackingDestinationLineNumber();
476 if ((*iter)->applied()) {
477 for (
int i = 0; i < (*iter)->sourceLineCount(); ++i) {
478 sourceLines.
append((*iter)->sourceLineAt(i)->string());
480 startPos = (*iter)->trackingDestinationLineEnd();
481 }
else if (startPos < editLineNumber) {
482 startPos = editLineNumber;
485 int endPos = (iter == appliedEnd) ? editLineEnd : (*iter)->trackingDestinationLineNumber();
486 for (
int i = startPos; i < endPos; ++i) {
487 sourceLines.
append(oldLines.
at(i - editLineNumber));
492 for (DifferenceListIterator iter = iterBegin; iter != iterEnd; ++iter) {
495 insertPosition = m_differences.
erase(iterBegin, iterEnd);
498 StringListPair* pair =
new StringListPair(sourceLines, destinationLines);
501 table.createListsOfMarkers();
502 MarkerList sourceMarkers = pair->markerListFirst();
503 MarkerList destinationMarkers = pair->markerListSecond();
505 int currentSourceListLine = 0;
506 int currentDestinationListLine = 0;
507 MarkerListConstIterator sourceMarkerIter = sourceMarkers.
constBegin();
508 MarkerListConstIterator destinationMarkerIter = destinationMarkers.
constBegin();
509 const int terminatorLineNumber = sourceLines.
size() + destinationLines.
size() + 1;
513 while (sourceMarkerIter != sourceMarkers.
constEnd() || destinationMarkerIter != destinationMarkers.
constEnd()) {
514 int nextSourceListLine = sourceMarkerIter != sourceMarkers.
constEnd() ? (*sourceMarkerIter)->offset() : terminatorLineNumber;
515 int nextDestinationListLine = destinationMarkerIter != destinationMarkers.
constEnd() ? (*destinationMarkerIter)->offset() : terminatorLineNumber;
518 int linesToSkip = qMin(nextDestinationListLine - currentDestinationListLine, nextSourceListLine - currentSourceListLine);
519 currentSourceListLine += linesToSkip;
520 currentDestinationListLine += linesToSkip;
521 Difference* diff =
new Difference(sourceLineNumber + currentSourceListLine, destinationLineNumber + currentDestinationListLine);
522 if (nextSourceListLine == currentSourceListLine) {
523 processStartMarker(diff, sourceLines, sourceMarkerIter, currentSourceListLine,
true);
525 if (nextDestinationListLine == currentDestinationListLine) {
526 processStartMarker(diff, destinationLines, destinationMarkerIter, currentDestinationListLine,
false);
528 computeDiffStats(diff);
529 Q_ASSERT(diff->type() != Difference::Unchanged);
531 diff->setTrackingDestinationLineNumber(diff->destinationLineNumber());
532 insertPosition = m_differences.
insert(insertPosition, diff);
537 for (; insertPosition != m_differences.
end(); ++insertPosition) {
538 (*insertPosition)->setTrackingDestinationLineNumber((*insertPosition)->trackingDestinationLineNumber() + (newLines.
size() - oldLines.
size()));
540 return qMakePair(inserted, removed);
544void DiffModel::computeDiffStats(
Difference* diff)
546 if (diff->sourceLineCount() > 0 && diff->destinationLineCount() > 0) {
547 diff->setType(Difference::Change);
548 }
else if (diff->sourceLineCount() > 0) {
549 diff->setType(Difference::Delete);
550 }
else if (diff->destinationLineCount() > 0) {
551 diff->setType(Difference::Insert);
557void DiffModel::processStartMarker(
Difference* diff,
const QStringList& lines, MarkerListConstIterator& currentMarker,
int& currentListLine,
bool isSource)
559 Q_ASSERT((*currentMarker)->type() == Marker::Start);
561 Q_ASSERT((*currentMarker)->type() == Marker::End);
562 int nextDestinationListLine = (*currentMarker)->offset();
563 for (; currentListLine < nextDestinationListLine; ++currentListLine) {
565 diff->addSourceLine(lines.
at(currentListLine));
567 diff->addDestinationLine(lines.
at(currentListLine));
571 currentListLine = nextDestinationListLine;
574#include "moc_diffmodel.cpp"
A model describing the differences between two files.
QPair< QList< Difference * >, QList< Difference * > > linesChanged(const QStringList &oldLines, const QStringList &newLines, int editLineNumber)
oldlines - lines that were removed.
void determineInlineDifferences()
This method will calculate the differences between the individual strings and store them as Markers.
void applyQuietly(bool apply)
Apply without emitting any signals.
Computes the Levenshtein distance between two sequences.
unsigned int createTable(SequencePair *sequences)
This calculates the levenshtein distance of 2 sequences.
QString path(const QString &relativePath)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
iterator erase(const_iterator begin, const_iterator end)
qsizetype indexOf(const AT &value, qsizetype from) const const
iterator insert(const_iterator before, parameter_type value)
bool isEmpty() const const
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QString arg(Args &&... args) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
int localeAwareCompare(QStringView s1, QStringView s2)
QString mid(qsizetype position, qsizetype n) const const