Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
66fe6f1
feat: add QDiffTextBrowser class and update CMake configuration
djad04 Jul 7, 2025
9c2ce16
feat: implement LineNumberArea class for QDiffTextBrowser integration
djad04 Jul 7, 2025
323bee2
feat:QDiffTextBrowser class explicit constructor and method declarations
djad04 Jul 8, 2025
1c0dc64
refactor: reorganize QDiffTextBrowser integration by moving LineNumbe…
djad04 Jul 18, 2025
80e369b
feat: add QLineNumberArea class for line numbering in QDiffTextBrowser
djad04 Jul 18, 2025
c45f768
feat: enhance QDiffTextBrowser with line numbering functionality
djad04 Jul 18, 2025
e051720
refactor(CMake): reorganize source files
djad04 Jul 18, 2025
e38caf6
feat: enhance line number display and add dynamic font scaling
djad04 Jul 18, 2025
24d633b
feat: implement diff Text highlighting and setDiffresult
djad04 Jul 18, 2025
50f69e8
feat(QDiffTextBrowser): implement custom line highlighting in paint e…
djad04 Jul 18, 2025
146752d
refactor(QDiffTextBrowser): Replace hardcoded values with named const…
djad04 Jul 18, 2025
24ce66b
feat(QDiffTextBrowser): add text colors and block spacing for diff hi…
djad04 Jul 20, 2025
f1dd771
refactor: improve line number rendering and add destructor
djad04 Jul 20, 2025
6df91d8
fix: lineNumberArea resizing and adding LINE_NUMBER_TEXT_WIDTH_RATIO
djad04 Jul 21, 2025
7cd84d7
build: add /permissive- flag for MSVC compiler to run memory safety t…
djad04 Jul 28, 2025
2d5ff4c
docs: remove outdated TODO comments from source files
djad04 Jul 29, 2025
0bc1b6b
Merge pull request #5 from djad04/feature/custom-diff-textbrowser
djad04 Jul 29, 2025
f5d3fd5
refactor(DTLAlgorithm): remove char-by-char diff and simplify logic
djad04 Jul 30, 2025
3729493
refactor(DMPAlgorithm): improve line-by-line diff calculation and rem…
djad04 Aug 2, 2025
c8d44f8
feat(DMPAlgorithm): replace char-by-char diff with word-by-word diff …
djad04 Aug 2, 2025
a276654
refactor(DMP): make diff utility methods public and update diffing di…
djad04 Aug 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 29 additions & 22 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

if(MSVC)
add_compile_options(/Zc:__cplusplus)
add_compile_options(/permissive- /Zc:__cplusplus)
endif()

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Widgets LinguistTools)
Expand All @@ -19,21 +19,27 @@ find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Widgets LinguistTool
set(TS_FILES src/QDiffX_en_150.ts)

set(PROJECT_SOURCES
main.cpp
main.cpp
src/QDiffWidget.cpp
src/QDiffTextBrowser.cpp
src/QLineNumberArea.cpp
)
set(PROJECT_HEADERS
src/QDiffWidget.h
src/QDiffTextBrowser.h
src/QLineNumberArea.h
)

set(QDIFFX_CORE_SOURCES
src/QDiffWidget.cpp
src/DMP/diff_match_patch.cpp
src/DTLAlgorithm.cpp
src/DMPAlgorithm.cpp
src/QAlgorithmRegistry.cpp
src/QAlgorithmManager.cpp
src/QAlgorithmException.cpp
src/DMP/diff_match_patch.cpp
src/DTLAlgorithm.cpp
src/DMPAlgorithm.cpp
src/QAlgorithmRegistry.cpp
src/QAlgorithmManager.cpp
src/QAlgorithmException.cpp
)

set(QDIFFX_CORE_HEADERS
src/QDiffWidget.h
src/DMP/diff_match_patch.h
src/DTLAlgorithm.h
src/DMPAlgorithm.h
Expand Down Expand Up @@ -62,36 +68,37 @@ if(${QT_VERSION_MAJOR} GREATER_EQUAL 6)
qt_add_executable(QDiffX
MANUAL_FINALIZATION
${PROJECT_SOURCES}
${PROJECT_HEADERS}
${TS_FILES}
)
# Define target properties for Android with Qt 6 as:
# set_property(TARGET QDiffX APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR
# ${CMAKE_CURRENT_SOURCE_DIR}/android)
# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation
target_link_libraries(QDiffX PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets QDiffXCore)
target_include_directories(QDiffX PRIVATE ${CMAKE_SOURCE_DIR}/src)
qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
target_link_libraries(QDiffX PRIVATE Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Widgets QDiffXCore)
target_include_directories(QDiffX PRIVATE ${CMAKE_SOURCE_DIR}/src)
qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
else()
if(ANDROID)
add_library(QDiffX SHARED
${PROJECT_SOURCES}
)
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(QDiffX
${PROJECT_SOURCES}
)
endif()
# Define properties for Android with Qt 5 after find_package() calls as:
# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android")
else()
add_executable(QDiffX
${PROJECT_SOURCES}
)
endif()

qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES})
endif()

# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
if(${QT_VERSION} VERSION_LESS 6.1.0)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.QDiffX)
set(BUNDLE_ID_OPTION MACOSX_BUNDLE_GUI_IDENTIFIER com.example.QDiffX)
endif()
set_target_properties(QDiffX PROPERTIES
${BUNDLE_ID_OPTION}
Expand Down
2 changes: 2 additions & 0 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ int main(int argc, char *argv[])
}
}
QDiffX::QDiffWidget w;
w.setContent("sdnk\nlsdk\nf\n", "aknf\nakf\nlkfn\n");
w.setGeometry(0,0,400,800);
w.show();
return a.exec();
}
4 changes: 2 additions & 2 deletions src/DMP/diff_match_patch.h
Original file line number Diff line number Diff line change
Expand Up @@ -255,7 +255,7 @@ class diff_match_patch {
* encoded text2 and the List of unique strings. The zeroth element
* of the List of unique strings is intentionally blank.
*/
protected:
public:
QList<QVariant> diff_linesToChars(const QString &text1, const QString &text2); // return elems 0 and 1 are QString, elem 2 is QStringList

/**
Expand All @@ -276,7 +276,7 @@ class diff_match_patch {
* @param diffs LinkedList of Diff objects.
* @param lineArray List of unique strings.
*/
private:
public:
void diff_charsToLines(QList<Diff> &diffs, const QStringList &lineArray);

/**
Expand Down
87 changes: 62 additions & 25 deletions src/DMPAlgorithm.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
#include "DMPAlgorithm.h"
#include <QRegularExpression>
#include <QRegularExpressionMatchIterator>
#include <QMap>
#include <QChar>
#include <QDebug>

namespace QDiffX{

Expand Down Expand Up @@ -36,32 +41,28 @@ QDiffX::QDiffResult QDiffX::DMPAlgorithm::calculateDiff(const QString &leftFile,
dmpChanges = diffLineByLine(leftFile, rightFile);
break;

case DiffMode::CharByChar:
dmpChanges = diffCharByChar(leftFile, rightFile);
case DiffMode::WordByWord:
dmpChanges = diffWordByWord(leftFile, rightFile);
break;

case DiffMode::Auto:
default:
dmpChanges = m_dmp.diff_main(leftFile, rightFile);
m_dmp.diff_cleanupSemantic(dmpChanges);
m_dmp.diff_cleanupEfficiency(dmpChanges);
dmpChanges = diffLineByLine(leftFile, rightFile);

break;
}


QList<QDiffX::DiffChange> changes = convertDiffList(dmpChanges);

// Calculate line numbers for the changes
calculateLineNumbers(changes, leftFile, rightFile);

result.setChanges(changes);
result.setSuccess(true);

// Add metadata about the algorithm used
QMap<QString, QVariant> metadata;
metadata["algorithm"] = "DMP";
metadata["mode"] = (mode == DiffMode::LineByLine) ? "line" :
(mode == DiffMode::CharByChar) ? "char" : "auto";
(mode == DiffMode::WordByWord) ? "word" : "auto";
metadata["total_changes"] = changes.size();
result.setMetaData(metadata);

Expand All @@ -72,28 +73,62 @@ QDiffX::QDiffResult QDiffX::DMPAlgorithm::calculateDiff(const QString &leftFile,

return result;
}
QList<Diff> DMPAlgorithm::diffCharByChar(const QString &leftFile, const QString &rightFile)


QList<Diff> DMPAlgorithm::diffWordByWord(const QString &leftFile, const QString &rightFile)
{
// checkLines=false for pure character-by-character comparison
QList<Diff> diffs = m_dmp.diff_main(leftFile, rightFile, false);
QString modifiedLeft = leftFile;
QString modifiedRight = rightFile;


modifiedLeft.replace("\n", "§NEWLINE§");
modifiedRight.replace("\n", "§NEWLINE§");

// Replace spaces with newlines temporarily
modifiedLeft.replace(" ", "\n");
modifiedRight.replace(" ", "\n");

QList<QVariant> result = m_dmp.diff_linesToChars(modifiedLeft, modifiedRight);

QString chars1 = result[0].toString();
QString chars2 = result[1].toString();
QStringList lineArray = result[2].toStringList();
qDebug()<< result[0].toString() << "\n" << result[1].toString() << "\n"<< result[2].toStringList(); ;

QList<Diff> diffs = m_dmp.diff_main(chars1, chars2);
m_dmp.diff_charsToLines(diffs, lineArray);


for (Diff &diff : diffs) {
diff.text.replace("\n", " ");
diff.text.replace("§NEWLINE§", "\n");
qDebug() << diff.toString() << "\n";
}

// Step 2: Apply cleanup for better results
m_dmp.diff_cleanupSemantic(diffs);
m_dmp.diff_cleanupEfficiency(diffs);

return diffs;
}



QList<Diff> DMPAlgorithm::diffLineByLine(const QString &leftFile, const QString &rightFile)
{
// Use DMP's integrated line mode by setting checklines=true
QList<Diff> diffs = m_dmp.diff_main(leftFile, rightFile, true);

// Apply cleanup for better results
m_dmp.diff_cleanupSemantic(diffs);
m_dmp.diff_cleanupEfficiency(diffs);
QList<QVariant> lineResult = m_dmp.diff_linesToChars(leftFile, rightFile);

return diffs;
// Extract the elements:
QString chars1 = lineResult[0].toString();
QString chars2 = lineResult[1].toString();
QStringList lineArray = lineResult[2].toStringList(); // line mapping

// Diff the encoded strings
QList<Diff> lineDiffs = m_dmp.diff_main(chars1, chars2);

// Convert back to lines
m_dmp.diff_charsToLines(lineDiffs, lineArray);


return lineDiffs;
}

AlgorithmCapabilities DMPAlgorithm::getCapabilities() const
Expand All @@ -102,9 +137,9 @@ AlgorithmCapabilities DMPAlgorithm::getCapabilities() const
caps.supportsLargeFiles = false;
caps.supportsUnicode = true;
caps.supportsBinary = false;
caps.supportsLineByLine = true; // Has diff_lineMode()
caps.supportsCharByChar = true; // Default character-level precision
caps.supportsWordByWord = false;
caps.supportsLineByLine = true;
caps.supportsCharByChar = false;
caps.supportsWordByWord = true;
caps.maxRecommendedSize = 1024 * 1024;
caps.description = "Reimplemented Google diff-match-patch,deprecated Qt4 components Replaced and updated to modern C++, optimized performance";

Expand Down Expand Up @@ -182,19 +217,21 @@ QList<DiffChange> DMPAlgorithm::convertDiffList(const QList<Diff> &dmpDiffs) con
{
QList<QDiffX::DiffChange> changes;
int position =0;
int line = 1;

for(auto &diff : dmpDiffs){
DiffChange change;
change.operation = convertOperation(diff.operation) ;
change.text = diff.text ;
change.lineNumber = -1; // will be calculated later using calculateLineNumbers()
change.lineNumber = line; // will be calculated later using calculateLineNumbers()
change.position = position;

changes.append(change);

if (diff.operation != DELETE) {
position += diff.text.length();
}
line++;
}
return changes;
}
Expand Down
4 changes: 3 additions & 1 deletion src/DMPAlgorithm.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class DMPAlgorithm : public QDiffAlgorithm
// QDiffAlgorithm interface Implementation
QDiffResult calculateDiff(const QString &leftFile, const QString &rightFile, DiffMode = DiffMode::Auto) override;

QList<Diff> diffCharByChar(const QString &leftFile, const QString &rightFile);
QList<Diff> diffWordByWord(const QString &leftFile, const QString &rightFile);
QList<Diff> diffLineByLine(const QString &leftFile, const QString &rightFile);

QString getName() const override { return "Diff-Match-Patch-GoogleAlgorithme-Modernized"; }
Expand All @@ -37,10 +37,12 @@ class DMPAlgorithm : public QDiffAlgorithm
bool isRecommendedFor(const QString &leftText, const QString &rightText) const override;

double calculateSimilarity(const QList<DiffChange> &changes, const QString &leftText, const QString &rightText) const;

private:
DiffOperation convertOperation(Operation dmpOp) const;
QList<DiffChange> convertDiffList(const QList<Diff>& dmpDiffs) const;
void calculateLineNumbers(QList<DiffChange> &changes,const QString &leftFile,const QString rightFile) const;


private:

Expand Down
Loading
Loading