Browse Source

Added files indicators

Alexey Edelev 7 years ago
parent
commit
9d544d53a6

+ 4 - 2
NiceGit.pro

@@ -28,7 +28,8 @@ SOURCES += \
     taglistmodel.cpp \
     tooltipviewmodel.cpp \
     gitconsole.cpp \
-    colorhandler.cpp
+    colorhandler.cpp \
+    diffmodel.cpp
 
 HEADERS += \
     githandler.h \
@@ -53,7 +54,8 @@ HEADERS += \
     taglistmodel.h \
     tooltipviewmodel.h \
     gitconsole.h \
-    colorhandler.h
+    colorhandler.h \
+    diffmodel.h
 
 RESOURCES += \
     resources.qrc

+ 40 - 0
diffmodel.cpp

@@ -0,0 +1,40 @@
+#include "diffmodel.h"
+
+DiffModel::DiffModel(const QString &path, QObject *parent) : QObject(parent)
+  ,m_path(path)
+  ,m_type(Unmodified)
+{
+
+}
+
+DiffModel::~DiffModel()
+{
+
+}
+
+DiffModel::DiffModel(const DiffModel& other) : QObject()
+{
+    m_type = other.m_type;
+    m_path = other.m_path;
+    m_data = other.m_data;
+}
+
+DiffModel& DiffModel::operator=(const DiffModel& other)
+{
+    if(this != &other) {
+        m_type = other.m_type;
+        emit typeChanged(m_type);
+        m_path = other.m_path;
+        m_data = other.m_data;
+        emit dataChanged(m_data);
+    }
+
+    return *this;
+}
+
+void DiffModel::append(const QString& unifiedData)
+{
+    m_data.append(unifiedData);
+    emit dataChanged(m_data);
+}
+

+ 91 - 0
diffmodel.h

@@ -0,0 +1,91 @@
+#ifndef DIFFMODEL_H
+#define DIFFMODEL_H
+
+#include <QObject>
+#include <QString>
+
+#include <git2/diff.h>
+
+class DiffModel : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QString path READ path CONSTANT)
+    Q_PROPERTY(QString data READ data NOTIFY dataChanged)
+    Q_PROPERTY(int type READ type NOTIFY typeChanged)
+    Q_PROPERTY(quint16 similarity READ similarity NOTIFY similarityChanged)
+    Q_ENUMS(DiffType)
+public:
+    enum DiffType {
+        Unmodified = GIT_DELTA_UNMODIFIED,
+        Added = GIT_DELTA_ADDED,
+        Deleted = GIT_DELTA_DELETED,
+        Modified = GIT_DELTA_MODIFIED,
+        Renamed = GIT_DELTA_RENAMED,
+        Copied = GIT_DELTA_COPIED,
+        Ignored = GIT_DELTA_IGNORED,
+        Untracked = GIT_DELTA_UNTRACKED,
+        TypeChange = GIT_DELTA_TYPECHANGE,
+        Unreadable = GIT_DELTA_UNREADABLE,
+        Conflicted = GIT_DELTA_CONFLICTED
+    };
+
+    explicit DiffModel(const QString& path = QString(), QObject *parent = 0);
+    DiffModel(const DiffModel& other);
+    DiffModel& operator=(const DiffModel& other);
+    ~DiffModel();
+
+    void append(const QString& unifiedData);
+
+    QString data() const
+    {
+        return m_data;
+    }
+
+    int type() const
+    {
+        return m_type;
+    }
+
+    QString path() const
+    {
+        return m_path;
+    }
+
+    void setType(int type)
+    {
+        if(m_type != type) {
+            m_type = type;
+            emit typeChanged(m_type);
+        }
+    }
+
+    quint16 similarity() const
+    {
+        return m_similarity;
+    }
+
+public slots:
+    void setSimilarity(quint16 similarity)
+    {
+        if (m_similarity == similarity)
+            return;
+
+        m_similarity = similarity;
+        emit similarityChanged(similarity);
+    }
+
+signals:
+    void dataChanged(QString data);
+
+    void typeChanged(int type);
+
+    void similarityChanged(quint16 similarity);
+
+private:
+    QString m_path;
+    int m_type;
+    QString m_data;
+    quint16 m_similarity;
+};
+
+#endif // DIFFMODEL_H

+ 49 - 16
gitdiff.cpp

@@ -16,19 +16,32 @@ GitDiff::GitDiff(git_commit* a, git_commit* b, GitRepository *repository) : QObj
     readBody(a, b);
 }
 
+GitDiff::~GitDiff()
+{
+    reset();
+}
+
 void GitDiff::readBody(git_commit *a, git_commit *b)
 {
     git_diff *diff = nullptr;
 
-    git_tree *a_tree = nullptr;
-    git_tree *b_tree = nullptr;
+    git_tree *aTree = nullptr;
+    git_tree *bTree = nullptr;
 
+    git_diff_find_options similarityOpts;
 
-    git_commit_tree(&a_tree, a);
-    git_commit_tree(&b_tree, b);
+    if(a != nullptr) {
+        git_commit_tree(&aTree, a);
+    }
 
-    git_diff_tree_to_tree(&diff, m_repository->raw(), a_tree, b_tree, nullptr);
+    if(b != nullptr) {
+        git_commit_tree(&bTree, b);
+    }
 
+    git_diff_tree_to_tree(&diff, m_repository->raw(), aTree, bTree, nullptr);
+
+    git_diff_find_init_options(&similarityOpts, GIT_DIFF_FIND_OPTIONS_VERSION);
+    git_diff_find_similar(diff, &similarityOpts);
 
     git_diff_print(diff,
                    GIT_DIFF_FORMAT_PATCH,
@@ -40,10 +53,10 @@ void GitDiff::readBody(git_commit *a, git_commit *b)
         QString prefix("<font color=\"%1\">%2");
         QString suffix("</font><br/>");
         GitDiff* diff = static_cast<GitDiff*>(payload);
-        QString fileName(delta->new_file.path);
-        if(line->origin == GIT_DIFF_LINE_FILE_HDR) {
-            return 0;
-        }
+        QString newFileName(delta->new_file.path);
+        QString oldFileName(delta->old_file.path);
+
+        QString diffData;
 
         switch(line->origin) {
         case GIT_DIFF_LINE_ADDITION:
@@ -66,19 +79,38 @@ void GitDiff::readBody(git_commit *a, git_commit *b)
             prefix = prefix.arg(line->origin);
         }
 
-        diff->m_diffList[fileName].append(prefix);
-        diff->m_diffList[fileName].append(QString::fromUtf8(line->content, line->content_len).toHtmlEscaped().replace(" ", "&nbsp;"));
-        diff->m_diffList[fileName].append(suffix);
+        if(!diff->m_diffList.contains(newFileName)) {
+            diff->m_diffList.insert(newFileName, QPointer<DiffModel>(new DiffModel(newFileName, diff)));
+        }
+
+        if(line->origin != GIT_DIFF_LINE_FILE_HDR) { //Add line only in case if origin is not file header
+            diffData = QString::fromUtf8(line->content, line->content_len);
+        } else if(delta->status == GIT_DELTA_RENAMED){ //else check the similarity
+            if(delta->similarity == 100) {
+                diffData = QString(oldFileName + " -> " + newFileName);
+            }
+            diff->m_diffList[newFileName]->setSimilarity(delta->similarity);
+        }
+
+        if(!diffData.isEmpty()) {
+            diff->m_diffList[newFileName]->append(prefix);
+            diff->m_diffList[newFileName]->append(diffData.toHtmlEscaped().replace(" ", "&nbsp;"));
+            diff->m_diffList[newFileName]->append(suffix);
+        }
+        diff->m_diffList[newFileName]->setType(delta->status);
         return 0;
     }, this);
 
     git_diff_free(diff);
-    git_tree_free(a_tree);
-    git_tree_free(b_tree);
+    git_tree_free(aTree);
+    git_tree_free(bTree);
 }
 
 void GitDiff::reset()
 {
+    foreach (QPointer<DiffModel> model, m_diffList) {
+        model.clear();
+    }
     m_diffList.clear();
 }
 
@@ -87,7 +119,8 @@ QStringList GitDiff::files()
     return m_diffList.keys();
 }
 
-QString GitDiff::unified(const QString& file)
+DiffModel* GitDiff::model(const QString& file)
 {
-    return m_diffList.value(file);
+    DiffModel* model = m_diffList.value(file).data();
+    return model;
 }

+ 6 - 4
gitdiff.h

@@ -2,9 +2,11 @@
 #define GITDIFF_H
 
 #include <QObject>
-#include <QHash>
+#include <QMap>
 #include <QString>
 
+#include <diffmodel.h>
+
 struct git_commit;
 
 class GitRepository;
@@ -16,16 +18,16 @@ class GitDiff : public QObject
 
 public:
     GitDiff(git_commit* a, git_commit* b, GitRepository* repository);
-    ~GitDiff(){}
+    ~GitDiff();
     void readBody(git_commit* a, git_commit* b);
     void reset();
 
-    Q_INVOKABLE QString unified(const QString& file);
+    Q_INVOKABLE DiffModel* model(const QString& file);
 
     QStringList files();
 
 private:
-    QHash<QString, QString> m_diffList;
+    QMap<QString, QPointer<DiffModel> > m_diffList;
     GitRepository* m_repository;
 };
 

BIN
images/diff-added.png


+ 12 - 0
images/diff-added.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="14px" height="16px" viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
+    <title>diff-added</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Octicons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="diff-added" fill="#000000">
+            <path d="M13,1 L1,1 C0.45,1 0,1.45 0,2 L0,14 C0,14.55 0.45,15 1,15 L13,15 C13.55,15 14,14.55 14,14 L14,2 C14,1.45 13.55,1 13,1 L13,1 Z M13,14 L1,14 L1,2 L13,2 L13,14 L13,14 Z M6,9 L3,9 L3,7 L6,7 L6,4 L8,4 L8,7 L11,7 L11,9 L8,9 L8,12 L6,12 L6,9 L6,9 Z" id="Shape"></path>
+        </g>
+    </g>
+</svg>

BIN
images/diff-ignored.png


+ 12 - 0
images/diff-ignored.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="14px" height="16px" viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
+    <title>diff-ignored</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Octicons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="diff-ignored" fill="#000000">
+            <path d="M13,1 L1,1 C0.45,1 0,1.45 0,2 L0,14 C0,14.55 0.45,15 1,15 L13,15 C13.55,15 14,14.55 14,14 L14,2 C14,1.45 13.55,1 13,1 L13,1 Z M13,14 L1,14 L1,2 L13,2 L13,14 L13,14 Z M4.5,12 L3,12 L3,10.5 L9.5,4 L11,4 L11,5.5 L4.5,12 L4.5,12 Z" id="Shape"></path>
+        </g>
+    </g>
+</svg>

BIN
images/diff-modified.png


+ 12 - 0
images/diff-modified.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="14px" height="16px" viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
+    <title>diff-modified</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Octicons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="diff-modified" fill="#000000">
+            <path d="M13,1 L1,1 C0.45,1 0,1.45 0,2 L0,14 C0,14.55 0.45,15 1,15 L13,15 C13.55,15 14,14.55 14,14 L14,2 C14,1.45 13.55,1 13,1 L13,1 Z M13,14 L1,14 L1,2 L13,2 L13,14 L13,14 Z M4,8 C4,6.34 5.34,5 7,5 C8.66,5 10,6.34 10,8 C10,9.66 8.66,11 7,11 C5.34,11 4,9.66 4,8 L4,8 Z" id="Shape"></path>
+        </g>
+    </g>
+</svg>

BIN
images/diff-removed.png


+ 12 - 0
images/diff-removed.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="14px" height="16px" viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
+    <title>diff-removed</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Octicons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="diff-removed" fill="#000000">
+            <path d="M13,1 L1,1 C0.45,1 0,1.45 0,2 L0,14 C0,14.55 0.45,15 1,15 L13,15 C13.55,15 14,14.55 14,14 L14,2 C14,1.45 13.55,1 13,1 L13,1 Z M13,14 L1,14 L1,2 L13,2 L13,14 L13,14 Z M11,9 L3,9 L3,7 L11,7 L11,9 L11,9 Z" id="Shape"></path>
+        </g>
+    </g>
+</svg>

BIN
images/diff-renamed.png


+ 12 - 0
images/diff-renamed.svg

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="14px" height="16px" viewBox="0 0 14 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 40.3 (33839) - http://www.bohemiancoding.com/sketch -->
+    <title>diff-renamed</title>
+    <desc>Created with Sketch.</desc>
+    <defs></defs>
+    <g id="Octicons" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="diff-renamed" fill="#000000">
+            <path d="M6,9 L3,9 L3,7 L6,7 L6,4 L11,8 L6,12 L6,9 L6,9 Z M14,2 L14,14 C14,14.55 13.55,15 13,15 L1,15 C0.45,15 0,14.55 0,14 L0,2 C0,1.45 0.45,1 1,1 L13,1 C13.55,1 14,1.45 14,2 L14,2 Z M13,2 L1,2 L1,14 L13,14 L13,2 L13,2 Z" id="Shape"></path>
+        </g>
+    </g>
+</svg>

+ 2 - 0
main.cpp

@@ -16,6 +16,7 @@
 #include <gitdiff.h>
 #include <gitoid.h>
 #include <tooltipviewmodel.h>
+#include <diffmodel.h>
 
 #include <graphlistmodel.h>
 #include <branchlistmodel.h>
@@ -45,6 +46,7 @@ int main(int argc, char *argv[])
     qmlRegisterUncreatableType<BranchListModel>("org.semlanik.nicegit", 1, 0, "BranchListModel", "Owned only by GitHandler");
     qmlRegisterUncreatableType<TagListModel>("org.semlanik.nicegit", 1, 0, "TagListModel", "Owned only by GitHandler");
     qmlRegisterUncreatableType<GitConsole>("org.semlanik.nicegit", 1, 0, "GitConsole", "Owned only by GitHandler");
+    qmlRegisterUncreatableType<DiffModel>("org.semlanik.nicegit", 1, 0, "DiffModel", "Owned only by GitHandler");
     qmlRegisterSingletonType<TooltipViewModel>("org.semlanik.nicegit", 1, 0,"TooltipViewModel",
                                                [](QQmlEngine *engine, QJSEngine *scriptEngine) -> QObject*
     {

+ 6 - 5
qml/CommitPlane.qml

@@ -18,6 +18,7 @@ Item {
         id: d
         property int viewportMargins: 20
         property int commitInfoWidth: 400
+        property QtObject diffModel: null
     }
 
     CommitInfo {
@@ -30,7 +31,7 @@ Item {
 
     DiffFiles {
         id: files
-        files: diff ? diff.files : null
+        diff: root.diff
         anchors.top: arrow.bottom
         anchors.topMargin: -10
         anchors.bottom: parent.bottom
@@ -38,8 +39,7 @@ Item {
         anchors.leftMargin: 20
         width: d.commitInfoWidth
         onOpenDiff: {
-            fileDiff.text = diff.unified(file)
-            currentFileName.text = qsTr("Diff for ") + file
+            d.diffModel = diff.model(file)
         }
     }
 
@@ -64,6 +64,7 @@ Item {
 
     Text {
         id: currentFileName
+        text: qsTr("Diff for ") + (d.diffModel ? d.diffModel.path : "")
         anchors.top: parent.top
         anchors.left: files.right
         anchors.leftMargin: 40
@@ -87,6 +88,7 @@ Item {
             height: fileDiff.contentHeight + 20
             Text {
                 id: fileDiff
+                text: d.diffModel ? d.diffModel.data : ""
                 anchors.top: parent.top
                 anchors.topMargin: 10
                 font.family: "Inconsolata"
@@ -96,8 +98,7 @@ Item {
     }
 
     onDiffChanged: {
-        fileDiff.text = ""
-        currentFileName.text = ""
+        d.diffModel = null
     }
 
     Rectangle {

+ 35 - 4
qml/DiffFiles.qml

@@ -1,20 +1,30 @@
 import QtQuick 2.0
+import QtGraphicalEffects 1.0
+
+import org.semlanik.nicegit 1.0
 
 ListView {
     id: root
-    property var files: null
+    property QtObject diff: null
     signal openDiff(var file)
     spacing: 10
-    model: files ? files : 0
+    model: diff ? diff.files : 0
     clip: true
     delegate: Item {
-        width: commitBodyText.width
+        property QtObject diffModel: root.diff.model(modelData)
+        width: commitBodyText.width + action.width + 10
         height: commitBodyText.height + 10
+//        Rectangle {
+//            color: "red"
+//            anchors.right: action.left
+//            height: parent.height
+//            width: parent.width*diffModel.similarity/100
+//        }
         Text {
             id: commitBodyText
             anchors.bottom: parent.bottom
             font.pointSize: 10
-            width: root.width
+            width: root.width - action.width - 10
             text: modelData
             elide: Text.ElideLeft
             horizontalAlignment: Text.AlignRight
@@ -28,5 +38,26 @@ ListView {
                 }
             }
         }
+        Image {
+            id: action
+            anchors.right: parent.right
+            anchors.verticalCenter: commitBodyText.verticalCenter
+            source: {
+                if(root.diff) {
+                    switch(diffModel.type) {
+                    case DiffModel.Added:
+                        return "qrc:///images/diff-added.png"
+                    case DiffModel.Deleted:
+                        return "qrc:///images/diff-removed.png"
+                    case DiffModel.Modified:
+                        return "qrc:///images/diff-modified.png"
+                    case DiffModel.Renamed:
+                        return "qrc:///images/diff-renamed.png"
+                    default:
+                        return "qrc:///images/diff-ignored.png"
+                    }
+                }
+            }
+        }
     }
 }

+ 1 - 1
qml/MainView.qml

@@ -33,7 +33,7 @@ FocusScope {
         commitsModel: _handler.commits
         graphModel: _handler.graph
         onCommitClicked: {
-            if(commit.diff == null) {
+            if(commit.diff === null) {
                 commitPlane.commit = null
                 commitPlane.diff = null
                 commitList.state = "full"

+ 10 - 0
resources.qrc

@@ -36,5 +36,15 @@
         <file>images/aim.svg</file>
         <file>images/aim.png</file>
         <file>qml/ConsoleControl.qml</file>
+        <file>images/diff-added.svg</file>
+        <file>images/diff-ignored.svg</file>
+        <file>images/diff-modified.svg</file>
+        <file>images/diff-removed.svg</file>
+        <file>images/diff-renamed.svg</file>
+        <file>images/diff-added.png</file>
+        <file>images/diff-ignored.png</file>
+        <file>images/diff-modified.png</file>
+        <file>images/diff-removed.png</file>
+        <file>images/diff-renamed.png</file>
     </qresource>
 </RCC>