Browse Source

Refactored diff TBB

Added basic implementation of workdir diff
Alexey Edelev 7 years ago
parent
commit
6150f66d61
13 changed files with 156 additions and 36 deletions
  1. 13 0
      commitgraph.cpp
  2. 2 0
      commitgraph.h
  3. 6 1
      commitmodel.cpp
  4. 8 4
      gitcommit.cpp
  5. 68 17
      gitdiff.cpp
  6. 12 5
      gitdiff.h
  7. 15 1
      githandler.cpp
  8. 2 0
      githandler.h
  9. 0 5
      graphpoint.h
  10. 10 1
      qml/CommitInfo.qml
  11. 8 2
      qml/CommitList.qml
  12. 2 0
      qml/CommitPlane.qml
  13. 10 0
      qml/MainView.qml

+ 13 - 0
commitgraph.cpp

@@ -172,3 +172,16 @@ GraphPoint* CommitGraph::point(int i)
 {
     return m_sortedPoints.at(i);
 }
+
+void CommitGraph::addWorkdir()
+{
+    GraphPoint* point = new GraphPoint(GitOid(), this);
+    m_points.insert(GitOid(), new GraphPoint(GitOid(), this));
+    m_sortedPoints.last()->addChildPoint(point);
+    m_sortedPoints.append(point);
+    for(int i = 0; i < m_sortedPoints.count(); i++) {
+        GraphPoint* point = m_sortedPoints.at(i);
+        point->setY(m_sortedPoints.count() - i - 1);
+    }
+    m_pointsModel->reset(m_sortedPoints);
+}

+ 2 - 0
commitgraph.h

@@ -26,6 +26,8 @@ public:
     void addHead(GitBranch* branch);
     void addHead(const GitOid& oid);
 
+    void addWorkdir();
+
     GraphListModel* points() const {
         return m_pointsModel;
     }

+ 6 - 1
commitmodel.cpp

@@ -42,7 +42,12 @@ CommitModel* CommitModel::fromGraph(CommitGraph *graph)
     QList<QPointer<GraphPoint> > points = graph->points()->container();
     for(int i = 0; i < points.count(); i++) {
         GraphPoint* point = points.at(i).data();
-        model->m_container.prepend(GitCommit::fromOid(point->oid()));
+        if(!point->oid().isValid()) {
+            qDebug() << "prepend empty";
+            model->m_container.prepend(nullptr);
+        } else {
+            model->m_container.prepend(GitCommit::fromOid(point->oid()));
+        }
 //        QPointer<GitTag> tag = commit->repository()->tags().value(commit->oid());
 //        if(!tag.isNull()) {
 //            point->setTag(tag.data()->name());

+ 8 - 4
gitcommit.cpp

@@ -83,10 +83,14 @@ QString GitCommit::summary() const
 GitDiff* GitCommit::diff()
 {
     if(m_diff.isNull()) {
-        git_commit *parent = nullptr;
-        git_commit_parent(&parent, raw(), 0);
-        m_diff = new GitDiff(parent, raw(), repository());
-        git_commit_free(parent);
+        git_commit *parentRaw = nullptr;
+        QScopedPointer<GitCommit> parent;
+        git_commit_parent(&parentRaw, raw(), 0);
+
+        if(parentRaw) {
+            parent.reset(new GitCommit(parentRaw, repository()));
+        }
+        m_diff = GitDiff::diff(parent.data(), this);
     }
     return m_diff.data();
 }

+ 68 - 17
gitdiff.cpp

@@ -1,44 +1,99 @@
 #include "gitdiff.h"
 
 #include <gitrepository.h>
+#include <diffmodel.h>
+#include <gitcommit.h>
 
 #include <QDebug>
 
 #include <git2/types.h>
 #include <git2/diff.h>
+#include <git2/tree.h>
 #include <git2/commit.h>
 
-GitDiff::GitDiff(git_commit* a, git_commit* b, GitRepository *repository) : QObject()
-  ,m_repository(repository)
+GitDiff::GitDiff(git_diff *raw, GitRepository* repository) : GitBase(raw, repository)
 {
     Q_ASSERT_X(m_repository, "GitDiff", "Repository of NULL");
     connect(m_repository, &GitRepository::destroyed, this, &GitDiff::deleteLater);
-    readBody(a, b);
 }
 
-GitDiff::~GitDiff()
+GitDiff* GitDiff::diff(GitCommit* a, GitCommit* b)
 {
-    reset();
-}
+    GitDiff* diff = nullptr;
 
-void GitDiff::readBody(git_commit *a, git_commit *b)
-{
-    git_diff *diff = nullptr;
+    git_diff *diffRaw = nullptr;
 
     git_tree *aTree = nullptr;
     git_tree *bTree = nullptr;
+    GitRepository* repo = nullptr;
+    bool isValid = false;
 
-    git_diff_find_options similarityOpts;
+    if(a == nullptr && b == nullptr) {
+        return diff;
+    }
 
     if(a != nullptr) {
-        git_commit_tree(&aTree, a);
+        git_commit_tree(&aTree, a->raw());
+        repo = a->repository();
+        isValid |= a->isValid();
     }
 
     if(b != nullptr) {
-        git_commit_tree(&bTree, b);
+        git_commit_tree(&bTree, b->raw());
+        if(repo != nullptr && repo != b->repository()) {
+            qDebug() << "Requested diff from different repositories";
+            return diff;
+        }
+        repo = b->repository();
+        isValid |= b->isValid();
     }
 
-    git_diff_tree_to_tree(&diff, m_repository->raw(), aTree, bTree, nullptr);
+    if(!isValid) {
+        qDebug() << "Both compared commits are invalid";
+        return diff;
+    }
+
+    git_diff_tree_to_tree(&diffRaw, repo->raw(), aTree, bTree, nullptr);
+    git_tree_free(aTree);
+    git_tree_free(bTree);
+
+    diff = new GitDiff(diffRaw,repo);
+    diff->readBody(diffRaw);
+
+    return diff;
+}
+
+GitDiff* GitDiff::diff(GitCommit* a)
+{
+    GitDiff* diff = nullptr;
+    git_diff *diffRaw = nullptr;
+    git_tree *aTree = nullptr;
+
+    if(a == nullptr) {
+        return nullptr;
+    }
+
+    git_commit_tree(&aTree, a->raw());
+
+    git_diff_tree_to_workdir(&diffRaw, a->repository()->raw(), aTree, nullptr);
+    git_tree_free(aTree);
+
+    diff = new GitDiff(diffRaw, a->repository());
+    diff->readBody(diffRaw);
+
+    return diff;
+}
+
+GitDiff::~GitDiff()
+{
+    reset();
+    git_diff_free(m_raw);
+}
+
+void GitDiff::readBody(git_diff *diff)
+{
+    git_diff_find_options similarityOpts;
+
 
     git_diff_find_init_options(&similarityOpts, GIT_DIFF_FIND_OPTIONS_VERSION);
     git_diff_find_similar(diff, &similarityOpts);
@@ -100,10 +155,6 @@ void GitDiff::readBody(git_commit *a, git_commit *b)
         diff->m_diffList[newFileName]->setType(delta->status);
         return 0;
     }, this);
-
-    git_diff_free(diff);
-    git_tree_free(aTree);
-    git_tree_free(bTree);
 }
 
 void GitDiff::reset()

+ 12 - 5
gitdiff.h

@@ -5,21 +5,25 @@
 #include <QMap>
 #include <QString>
 
-#include <diffmodel.h>
+#include <gitbase.h>
 
 struct git_commit;
 
 class GitRepository;
+class GitCommit;
+class DiffModel;
+struct git_diff;
 
-class GitDiff : public QObject
+class GitDiff : public GitBase<git_diff>
 {
     Q_OBJECT
     Q_PROPERTY(QStringList files READ files CONSTANT)
 
 public:
-    GitDiff(git_commit* a, git_commit* b, GitRepository* repository);
+    static GitDiff* diff(GitCommit* a, GitCommit* b);
+    static GitDiff* diff(GitCommit* a);
+
     ~GitDiff();
-    void readBody(git_commit* a, git_commit* b);
     void reset();
 
     Q_INVOKABLE DiffModel* model(const QString& file);
@@ -27,8 +31,11 @@ public:
     QStringList files();
 
 private:
+    GitDiff(git_diff* raw, GitRepository* repository);
+
+    void readBody(git_diff* diff);
+
     QMap<QString, QPointer<DiffModel> > m_diffList;
-    GitRepository* m_repository;
 };
 
 #endif // GITDIFF_H

+ 15 - 1
githandler.cpp

@@ -20,6 +20,7 @@
 #include <branchlistmodel.h>
 #include <taglistmodel.h>
 #include <gitconsole.h>
+#include <graphpoint.h>
 
 GitHandler::GitHandler() : QObject()
   ,m_repositories(new RepositoryModel(this))
@@ -100,10 +101,22 @@ GitDiff* GitHandler::diff(GitCommit* a, GitCommit* b)
 
     Q_ASSERT_X(a->repository() == b->repository(), "GitHandler", "Cross repository diff requested");
 
-    m_activeDiff = new GitDiff(a->raw(), b->raw(), a->repository());
+    m_activeDiff = GitDiff::diff(a, b);
+    return m_activeDiff.data();
+}
+
+GitDiff* GitHandler::diff()
+{
+    if(!m_activeDiff.isNull()) {
+        m_activeDiff->deleteLater();
+    }
+
+    QScopedPointer<GitCommit> commit(GitCommit::fromOid(activeRepo()->head()));
+    m_activeDiff = GitDiff::diff(commit.data());
     return m_activeDiff.data();
 }
 
+
 void GitHandler::setActiveDiff(GitDiff* activeDiff)
 {
     if (m_activeDiff == activeDiff)
@@ -151,6 +164,7 @@ void GitHandler::updateModels()
         qDebug() << "Next head " << branch->fullName();
         graph->addHead(branch);
     }
+    graph->addWorkdir();
 
     m_graph->deleteLater();
     m_graph = graph;

+ 2 - 0
githandler.h

@@ -34,6 +34,8 @@ public:
 
     Q_INVOKABLE GitDiff* diff(GitCommit* a, GitCommit* b);
 
+    Q_INVOKABLE GitDiff* diff(); //Dif of workdir
+
     Q_INVOKABLE void copy(const QString& sha1);
 
     RepositoryModel* repositories() const

+ 0 - 5
graphpoint.h

@@ -11,7 +11,6 @@ class GraphPoint : public QObject
     Q_PROPERTY(int x READ x WRITE setX NOTIFY xChanged)
     Q_PROPERTY(int y READ y WRITE setY NOTIFY yChanged)
     Q_PROPERTY(QString color READ color WRITE setColor NOTIFY colorChanged)
-    Q_PROPERTY(QString sha1 READ sha1 CONSTANT)
     Q_PROPERTY(QList<QObject*> childPoints READ childPoints CONSTANT)
     Q_PROPERTY(GitOid oid READ oid CONSTANT)
 
@@ -36,10 +35,6 @@ public:
         return m_commitOid;
     }
 
-    QString sha1() const {
-        return m_commitOid.toString();
-    }
-
     int childPointsCount() const {
         return m_childPoints.count();
     }

+ 10 - 1
qml/CommitInfo.qml

@@ -18,7 +18,16 @@ Item {
                 target: root
                 height: shortInfo.height
             }
+        },
+        State {
+            name: "hidden"
+            when: !root.visible
+            PropertyChanges {
+                target: root
+                height: 0
+            }
         }
+
     ]
 
     transitions: Transition {
@@ -53,7 +62,7 @@ Item {
     }
     Image {
         id: merge
-        visible: commit.isMerge
+        visible: commit ? commit.isMerge : false
         source: "qrc:///images/flow-merge.png"
         anchors.right: shortInfo.right
         anchors.rightMargin: 5

+ 8 - 2
qml/CommitList.qml

@@ -79,10 +79,9 @@ FlickPager {
                         width: root.width - graph.width - graphAnnotation.width
                         height: sha1.height
                         anchors.right: parent.right
-
                         Image {
                             id: marker
-                            visible: model.isMerge
+                            visible: model.isMerge ? true : false
                             source: "qrc:///images/flow-merge-16.png"
                         }
 
@@ -132,6 +131,13 @@ FlickPager {
                             if(mouse.button === Qt.RightButton) {
                                 commitMenu.popup()
                             } else {
+                                if(model.modelData == null) {
+                                    root.commitClicked(null)
+                                    //TODO: Because active commit is used in multiple places need to make it part of some model (e.g. git handler)
+                                    activeCommit = null
+                                    return
+                                }
+
                                 root.commitClicked(model.modelData)
                                 //TODO: Because active commit is used in multiple places need to make it part of some model (e.g. git handler)
                                 activeCommit = model.modelData;

+ 2 - 0
qml/CommitPlane.qml

@@ -28,6 +28,7 @@ Item {
         anchors.left: parent.left
         anchors.leftMargin: 20
         width: d.commitInfoWidth
+        visible: commit != null
     }
 
     DiffFiles {
@@ -46,6 +47,7 @@ Item {
 
     FlickPagerArrow {
         id: arrow
+        enabled: commit != null
         anchors.top: commitInfo.bottom
         source: commitInfo.state === "opened" ? "arrow-141-16" : "arrow-203-16"
         active: true

+ 10 - 0
qml/MainView.qml

@@ -33,6 +33,13 @@ FocusScope {
         commitsModel: _handler.commits
         graphModel: _handler.graph
         onCommitClicked: {
+            if(commit == null) {
+                commitPlane.commit = null
+                commitPlane.diff = _handler.diff()
+                commitList.state = "commitsOnly"
+                return;
+            }
+
             if(commit.diff === null) {
                 commitPlane.commit = null
                 commitPlane.diff = null
@@ -112,4 +119,7 @@ FocusScope {
 
     Tooltip {
     }
+//    Component.onCompleted: {
+//        commitPlane.diff = _handler.diff();
+//    }
 }