Browse Source

Refactor graph part

Rendering based on canvas
Alexey Edelev 10 năm trước cách đây
mục cha
commit
52bb6cad51
13 tập tin đã thay đổi với 265 bổ sung230 xóa
  1. 2 2
      NiceGit.pro
  2. 34 36
      commitgraph.cpp
  3. 12 4
      commitgraph.h
  4. 0 6
      commitviewmodel.cpp
  5. 0 39
      commitviewmodel.h
  6. 0 3
      gitcommit.cpp
  7. 1 12
      gitcommit.h
  8. 7 10
      githandler.cpp
  9. 21 0
      githandler.h
  10. 52 0
      graphpoint.cpp
  11. 75 0
      graphpoint.h
  12. 7 3
      main.cpp
  13. 54 115
      qml/MainView.qml

+ 2 - 2
NiceGit.pro

@@ -17,7 +17,7 @@ SOURCES += \
     commitmodel.cpp \
     universallistmodel.cpp \
     commitgraph.cpp \
-    commitviewmodel.cpp
+    graphpoint.cpp
 
 HEADERS += \
     githandler.h \
@@ -31,7 +31,7 @@ HEADERS += \
     commitmodel.h \
     universallistmodel.h \
     commitgraph.h \
-    commitviewmodel.h
+    graphpoint.h
 
 RESOURCES += \
     resources.qrc

+ 34 - 36
commitgraph.cpp

@@ -1,11 +1,13 @@
 #include "commitgraph.h"
 
-#include <git2/revwalk.h>
-#include <git2/commit.h>
-
 #include <gitcommit.h>
+#include <graphpoint.h>
+
 #include <QDateTime>
 
+#include <git2/revwalk.h>
+#include <git2/commit.h>
+
 CommitGraph::CommitGraph() : QObject()
 {
     qsrand(QDateTime::currentMSecsSinceEpoch());
@@ -13,12 +15,11 @@ CommitGraph::CommitGraph() : QObject()
 
 void CommitGraph::addHead(const GitOid &oid)
 {
+    //Random color generation to be replaced with resets
     int red = qrand() % 205 + 50;
     int green = qrand() % 205 + 50;
     int blue = qrand() % 205 + 50;
-
     m_color = QString::number(red, 16) + QString::number(green, 16) + QString::number(blue, 16);
-    qDebug() << m_color;
 
     git_revwalk* walk;
     git_revwalk_new(&walk, oid.repository()->raw());
@@ -28,13 +29,17 @@ void CommitGraph::addHead(const GitOid &oid)
 
     git_oid newOid;
     while(git_revwalk_next(&newOid, walk) == 0) {
-        qDebug() << "Next commit parents";
         GitOid commitOid(&newOid, oid.repository());
         GitCommit *commit = GitCommit::fromOid(commitOid);
         findParents(commit);
     }
 
     git_revwalk_free(walk);
+
+    qDebug() << "Update Y coordinate after head added";
+    for(int i = 0; i < m_sortedPoints.count(); i++) {
+        static_cast<GraphPoint*>(m_sortedPoints.at(i))->setY(i);
+    }
 }
 
 void CommitGraph::findParents(GitCommit* commit)
@@ -47,15 +52,16 @@ void CommitGraph::findParents(GitCommit* commit)
         GitOid parentOid(git_commit_id(commitRaw), commit->repository());
         commit = GitCommit::fromOid(parentOid);
         reverseList.push_front(parentOid);
+        if(m_points.contains(parentOid)) { //Finish parents lookup once parent found in tree. We will see nothing new in this branch
+            break;
+        }
+
         qDebug() << "Add commit to reverselist" << parentOid.toString();
         commitRaw = nullptr;
         git_commit_parent(&commitRaw, commit->raw(), 0);
-        if(m_commits.contains(parentOid)) { //Finish parents lookup once parent found in tree. We will see nothing new in this branch
-            break;
-        }
     }
 
-    if(reverseList.isEmpty()) {
+    if(reverseList.count() < 2) { //In case if only original commit in list, we didn't find anything new
         return;
     }
     addCommits(reverseList);
@@ -63,43 +69,35 @@ void CommitGraph::findParents(GitCommit* commit)
 
 void CommitGraph::addCommits(QList<GitOid>& reversList)
 {
-    GitCommit* parent;
-    GitCommit* commit;
+    GraphPoint* point = nullptr;
+    GraphPoint* parentPoint = nullptr;
 
     for(int i = 0; i < (reversList.count() - 1); i++) {
         GitOid& parentIter = reversList[i];
         GitOid& childIter = reversList[i + 1];
-        parent = m_commits.value(parentIter, nullptr);
-        if(parent == nullptr) {
-            //Ony in case if i == 0
-            parent = GitCommit::fromOid(parentIter);
-            m_commits.insert(parent->oid(), parent);
-            parent->m_color = m_color;
-            m_fullList.push_back(parent);
+        parentPoint = m_points.value(parentIter, nullptr);
+        if(parentPoint == nullptr) {
+            parentPoint = new GraphPoint(parentIter, this);
+            parentPoint->setColor(m_color);
+            m_sortedPoints.append(parentPoint);
+            m_points.insert(parentPoint->oid(), parentPoint);
         }
 
-        commit = m_commits.value(childIter, nullptr);
-        if(commit == nullptr) {
-            commit = GitCommit::fromOid(childIter);
-
-            //ViewModelPart
-            commit->m_x = parent->m_childrenCounter++;
-            commit->m_childrenCounter = commit->m_x;
-            commit->m_color = m_color;
-            if(commit->m_x == parent->m_x) { //TODO: Too dirty hack seems will not work with amount of commits more than 1
-                parent->m_color = commit->m_color;
-            }
-            //End ViewModelPart
+        point = m_points.value(childIter, nullptr);
+        if(point == nullptr) {
+            int x = parentPoint->x() + parentPoint->childPointsCount();
+            point = new GraphPoint(childIter, x, 0, m_color, this);
+            parentPoint->addChildPoint(point);
 
-            m_commits.insert(commit->oid(), commit);
+            m_points.insert(point->oid(), point);
 
             //Ordered commits
-            int parentPosition = m_fullList.indexOf(parent);
+            int parentPosition = m_sortedPoints.indexOf(parentPoint);
             if(parentPosition >= 0) {
-                m_fullList.insert(parentPosition + 1, commit);
+                m_sortedPoints.insert(parentPosition + 1, point);
             }
-            qDebug() << "New commit: " << commit->sha1() << commit->x() << commit->y();
-            qDebug() << "Parent commit: " << parent->sha1() << parent->x() << parent->y();
+            qDebug() << "New commit: " << point->oid().toString() << point->x() << point->y();
+            qDebug() << "New commit: " << parentPoint->oid().toString() << parentPoint->x() << parentPoint->y();
         }
     }
 }

+ 12 - 4
commitgraph.h

@@ -3,27 +3,35 @@
 
 #include <QObject>
 
+#include <gitoid.h>
+
 #include <QString>
 #include <QHash>
-#include <gitoid.h>
+#include <QObjectList>
 
 class GitCommit;
+class GraphPoint;
 
 class CommitGraph : public QObject
 {
+    Q_OBJECT
+    Q_PROPERTY(QList<QObject*> points READ points CONSTANT)
 public:
     CommitGraph();
     void addHead(const GitOid& oid);
 
-    QHash<GitOid, GitCommit*> m_commits;
-    QList<GitCommit*> m_fullList;
+    QList<QObject*> points() const {
+        return m_sortedPoints;
+    }
 
 private:
     void findParents(GitCommit *commit);
-
     void addCommits(QList<GitOid> &reversList);
 
     QString m_color;
+
+    QHash<GitOid, GraphPoint*> m_points;
+    QObjectList m_sortedPoints;
 };
 
 #endif // COMMITGRAPH_H

+ 0 - 6
commitviewmodel.cpp

@@ -1,6 +0,0 @@
-#include "commitviewmodel.h"
-
-CommitViewModel::CommitViewModel(CommitGraph *graph)
-{
-
-}

+ 0 - 39
commitviewmodel.h

@@ -1,39 +0,0 @@
-#ifndef COMMITVIEWMODEL_H
-#define COMMITVIEWMODEL_H
-
-#include <QObject>
-
-class CommitGraph;
-
-class CommitViewModel : public QObject
-{
-    Q_OBJECT
-    Q_PROPERTY(int x READ x CONSTANT)
-    Q_PROPERTY(int y READ y CONSTANT)
-    Q_PROPERTY(QString color READ color CONSTANT)
-
-public:
-    CommitViewModel(CommitGraph* graph);
-
-    int x() const
-    {
-        return m_x;
-    }
-
-    int y() const
-    {
-        return m_y;
-    }
-
-    QString color() const
-    {
-        return m_color;
-    }
-
-private:
-    int m_x;
-    int m_y;
-    QString m_color;
-};
-
-#endif // COMMITVIEWMODEL_H

+ 0 - 3
gitcommit.cpp

@@ -7,9 +7,6 @@
 #include <git2/commit.h>
 
 GitCommit::GitCommit(git_commit* raw, GitRepository* parent) : GitBase(raw, parent)
-  ,m_x(0)
-  ,m_y(0)
-  ,m_childrenCounter(0)
 {
     m_oid = GitOid(git_commit_id(m_raw), m_repository);
 }

+ 1 - 12
gitcommit.h

@@ -5,6 +5,7 @@
 
 #include <QDateTime>
 #include <QString>
+#include <QList>
 
 #include <git2/types.h>
 
@@ -18,9 +19,6 @@ class GitCommit : public GitBase<git_commit>
     Q_PROPERTY(QString sha1 READ sha1 NOTIFY commitChanged)
     Q_PROPERTY(QString shortSha1 READ shortSha1 NOTIFY commitChanged)
     Q_PROPERTY(bool isMerge READ isMerge NOTIFY commitChanged)
-    Q_PROPERTY(int x READ x NOTIFY commitChanged)
-    Q_PROPERTY(int y READ y NOTIFY commitChanged)
-    Q_PROPERTY(QString color READ color)
 
 public:
     GitCommit(git_commit* raw, GitRepository* parent);
@@ -35,9 +33,6 @@ public:
     QString sha1() const;
     QString shortSha1() const;
     bool isMerge() const;
-    int x() const { return m_x; }
-    int y() const { return m_y; }
-    QString color() const { return m_color; }
 
 public slots:
     void setAuthor(QString author);
@@ -55,12 +50,6 @@ private:
     QDateTime m_time;
     QString m_message;
     QString m_email;
-
-public:
-    int m_x;
-    int m_y;
-    int m_childrenCounter;
-    QString m_color;
 };
 
 #endif // GITCOMMIT_H

+ 7 - 10
githandler.cpp

@@ -10,6 +10,7 @@
 #include <git2.h>
 
 #include <commitgraph.h>
+#include <graphpoint.h>
 
 GitHandler::GitHandler() : QObject()
   ,m_repositories(new RepositoryModel(this))
@@ -52,16 +53,12 @@ void GitHandler::open(const QString &path)
         graph->addHead(branch->oid());
     }
 
-    foreach (GitCommit* commit, graph->m_fullList) {
-        qDebug() << commit->sha1();
-        commit->m_y = graph->m_fullList.indexOf(commit);
-    }
-
-    CommitModel* main = new CommitModel("main");
-    foreach (GitCommit* commitPtr, graph->m_commits) {
-        main->add(commitPtr);
-    }
-    m_commits.insert("main", main);
+    setGraph(graph);
+//    CommitModel* main = new CommitModel("main");
+//    foreach (GitCommit* commitPtr, graph->m_points) {
+//        main->add(commitPtr);
+//    }
+//    m_commits.insert("main", main);
     m_repositories->add(repo);
 }
 

+ 21 - 0
githandler.h

@@ -6,12 +6,15 @@
 #include <repositorymodel.h>
 
 class CommitModel;
+class CommitGraph;
+
 typedef QHash<QString, QPointer<CommitModel>> CommitModelContainer;
 
 class GitHandler : public QObject
 {
     Q_OBJECT
     Q_PROPERTY(RepositoryModel* repositories READ repositories NOTIFY repositoriesChanged)
+    Q_PROPERTY(CommitGraph* graph READ graph WRITE setGraph NOTIFY graphChanged)
 
 public:
     GitHandler();
@@ -26,15 +29,33 @@ public:
 
     Q_INVOKABLE CommitModel* modelByHead(const QString& head);
 
+    CommitGraph* graph() const
+    {
+        return m_graph;
+    }
+
+public slots:
+    void setGraph(CommitGraph* graph)
+    {
+        if (m_graph == graph)
+            return;
+
+        m_graph = graph;
+        emit graphChanged(graph);
+    }
+
 signals:
     void repositoriesChanged(RepositoryModel* repositories);
 
+    void graphChanged(CommitGraph* graph);
+
 protected:
     QString lastError() const;
 
 private:
     RepositoryModel* m_repositories;
     CommitModelContainer m_commits;
+    CommitGraph* m_graph;
 };
 
 #endif // GITHANDLER_H

+ 52 - 0
graphpoint.cpp

@@ -0,0 +1,52 @@
+#include "graphpoint.h"
+
+GraphPoint::GraphPoint(const GitOid &commitOid, QObject* parent) : QObject(parent)
+  ,m_commitOid(commitOid)
+  ,m_x(0)
+  ,m_y(0)
+{
+
+}
+
+GraphPoint::GraphPoint(const GitOid &commitOid, int x, int y, const QString &color, QObject *parent) : QObject(parent)
+  ,m_commitOid(commitOid)
+  ,m_x(x)
+  ,m_y(y)
+  ,m_color(color)
+{
+}
+
+GraphPoint::~GraphPoint()
+{
+}
+
+void GraphPoint::setX(int x)
+{
+    if (m_x == x) {
+        return;
+    }
+
+    m_x = x;
+    emit xChanged(x);
+}
+
+void GraphPoint::setY(int y)
+{
+    if (m_y == y) {
+        return;
+    }
+
+    m_y = y;
+    emit yChanged(y);
+}
+
+void GraphPoint::setColor(const QString& color)
+{
+    if (m_color == color) {
+        return;
+    }
+
+    m_color = color;
+    emit colorChanged(color);
+}
+

+ 75 - 0
graphpoint.h

@@ -0,0 +1,75 @@
+#ifndef GRAPHPOINT_H
+#define GRAPHPOINT_H
+
+#include <QList>
+#include <QObject>
+#include <gitoid.h>
+
+class GraphPoint : public QObject
+{
+    Q_OBJECT
+    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(QList<QObject*> childPoints READ childPoints CONSTANT)
+
+public:
+    GraphPoint(const GitOid& commitOid, QObject* parent = 0);
+    GraphPoint(const GitOid& commitOid, int x, int y, const QString& color, QObject* parent = 0);
+    ~GraphPoint();
+
+    int x() const
+    {
+        return m_x;
+    }
+
+    int y() const
+    {
+        return m_y;
+    }
+
+    QString color() const
+    {
+        return m_color;
+    }
+
+    const GitOid& oid() const
+    {
+        return m_commitOid;
+    }
+
+    int childPointsCount() const
+    {
+        return m_childPoints.count();
+    }
+
+    void addChildPoint(GraphPoint* point)
+    {
+        m_childPoints.append(point);
+    }
+
+    QList<QObject*> childPoints() const
+    {
+        return m_childPoints;
+    }
+
+public slots:
+    void setX(int x);
+    void setY(int y);
+    void setColor(const QString& color);
+
+signals:
+    void xChanged(int x);
+    void yChanged(int y);
+    void colorChanged(const QString& color);
+
+private:
+    GitOid m_commitOid;
+    QList<QObject*> m_childPoints;
+
+    int m_x;
+    int m_y;
+    QString m_color;
+};
+
+#endif // GRAPTHPOINT_H

+ 7 - 3
main.cpp

@@ -8,6 +8,8 @@
 #include <repositorymodel.h>
 #include <gitbranch.h>
 #include <commitmodel.h>
+#include <graphpoint.h>
+#include <commitgraph.h>
 
 #include <QDebug>
 
@@ -17,11 +19,13 @@ int main(int argc, char *argv[])
 
     QQuickView view;
 
-    qmlRegisterUncreatableType<GitHandler>("org.semlanik.nicegit", 1, 0, "GitHandler", "Global for qml");
+    qmlRegisterUncreatableType<CommitModel>("org.semlanik.nicegit", 1, 0, "CommitModel", "Owned only by GitHandler");
+    qmlRegisterUncreatableType<CommitGraph>("org.semlanik.nicegit", 1, 0, "CommitGraph", "Owned only by GitHandler");
+    qmlRegisterUncreatableType<GraphPoint>("org.semlanik.nicegit", 1, 0, "GraphPoint", "Owned only by GitHandler");
+    qmlRegisterUncreatableType<RepositoryModel>("org.semlanik.nicegit", 1, 0, "RepositoryModel", "Owned only by GitHandler");
     qmlRegisterUncreatableType<GitRepository>("org.semlanik.nicegit", 1, 0, "GitRepository", "Owned only by GitHandler");
     qmlRegisterUncreatableType<GitBranch>("org.semlanik.nicegit", 1, 0, "GitRepository", "Owned only by GitHandler");
-    qmlRegisterUncreatableType<RepositoryModel>("org.semlanik.nicegit", 1, 0, "RepositoryModel", "Owned only by GitHandler");
-    qmlRegisterUncreatableType<CommitModel>("org.semlanik.nicegit", 1, 0, "CommitModel", "Owned only by GitHandler");
+    qmlRegisterUncreatableType<GitHandler>("org.semlanik.nicegit", 1, 0, "GitHandler", "Global for qml");
 
 
     GitHandler handler;

+ 54 - 115
qml/MainView.qml

@@ -27,129 +27,68 @@ Item {
         }
     }
 
-    Item {
-    width:  childrenRect.width
-    height: childrenRect.height
-    anchors.right: parent.right
-    Repeater {
-        model: _handler.modelByHead("main")
-        Rectangle {
-            radius: 10
-            x: model.x*(width+20)
-            y: model.y*(height+10)
-            width: 100
-            height: 30
-            color: "#"+model.color;
-            Text {
-                id: sha1Lable
-                maximumLineCount: 8
-                text: model.shortSha1
-            }
-            MouseArea {
-                hoverEnabled: true
-                anchors.fill: parent
-                onEntered: {
-                    parent.state = "full"
-                }
-                onExited: {
-                    parent.state = "short"
-                }
-            }
-        }
-    }
-}
-//    Row {
+//    Item {
+//        width:  childrenRect.width
+//        height: childrenRect.height
 //        anchors.right: parent.right
-//        anchors.top: parent.top
-//        anchors.bottom: parent.bottom
 //        Repeater {
-//            model: ListModel {
-//                ListElement {
-//                    branch: "b3"
-//                }
-//                ListElement {
-//                    branch: "master"
-//                }
-//                ListElement {
-//                    branch: "b1"
-//                }
-//                ListElement {
-//                    branch: "b2"
+//            model: _handler.graph.points
+//            Rectangle {
+//                radius: 10
+//                x: model.modelData.x*(width+20)
+//                y: model.modelData.y*(height+10)
+//                width: 100
+//                height: 30
+//                color: "#"+model.modelData.color;
+//                MouseArea {
+//                    hoverEnabled: true
+//                    anchors.fill: parent
+//                    onEntered: {
+//                        parent.state = "full"
+//                    }
+//                    onExited: {
+//                        parent.state = "short"
+//                    }
 //                }
-//                ListElement {
-//                    branch: "b4"
+//                Component.onCompleted: {
+//                    console.log("model.x: " + _handler.graph.points.length)
 //                }
 //            }
+//        }
+//    }
 
-//            Column {
-//                width: 200
-//                Text {
-//                    id: branchName
-//                    text: "Branch:" + branch
-//                }
-//                ListView {
-//                    id: branchList
-//                    height: root.height
-//                    width: 200
-//                    model: _handler.modelByHead(branch)
-//                    delegate: Rectangle {
-//                        id: idRect
-//                        width: parent.width
-//                        height: 80
-//                        color: "#cccccc"
-//                        states: [
-//                            State {
-//                                name:"full"
-//                                PropertyChanges {
-//                                    target: sha1Lable
-//                                    text: model.sha1
-//                                }
-//                                PropertyChanges {
-//                                    target: idRect
-//                                    color: !model.isMerge ? "#dddddd" : "#aa6666"
-//                                }
-//                            },
-//                            State {
-//                                name:"short"
-//                                PropertyChanges {
-//                                    target: sha1Lable
-//                                    text: model.shortSha1
-//                                }
-//                                PropertyChanges {
-//                                    target: idRect
-//                                    color: "#cccccc"
-//                                }
-//                            }]
+    Canvas {
+        property int elementWidth: 20
+        property int elementHeight: 20
+        width: parent.width/2
+        height: _handler.graph.points.length*(elementWidth + 10)
+        onPaint: {
+            var ctx = getContext("2d")
+            for(var i = 0; i < _handler.graph.points.length; i++) {
+                var point = _handler.graph.points[i]
 
-//                        state: "short"
+                ctx.beginPath()
+                ctx.fillStyle = "#"+point.color
+                ctx.roundedRect(point.x*(elementWidth + 10), point.y*(elementHeight + 10), elementWidth, elementHeight, elementWidth, elementHeight)
+                ctx.fill()
+                ctx.closePath()
+
+                var childPoints = point.childPoints
+
+                for(var j = 0; j < childPoints.length; j++) {
+                    var childPoint = childPoints[j]
+                    ctx.beginPath()
+                    ctx.strokeStyle = "#"+point.color
+                    ctx.lineWidth = 2
+                    ctx.moveTo(point.x*(elementWidth + 10) + elementWidth/2, point.y*(elementHeight + 10) + elementHeight/2)
+                    ctx.lineTo(childPoint.x*(elementWidth + 10) + elementWidth/2, childPoint.y*(elementHeight + 10) + elementHeight/2)
+                    ctx.stroke()
+                    ctx.closePath()
+                }
+            }
+        }
+    }
 
-//                        Column {
-//                            width: branchList.width
-//                            Text {
-//                                id: sha1Lable
-//                                width: branchList.width
-//                                maximumLineCount: 8
-//                                text: model.shortSha1
-//                            }
-//                            Text {
-//                                text: model.message
-//                            }
-//                        }
-//                        MouseArea {
-//                            hoverEnabled: true
-//                            anchors.fill: parent
-//                            onEntered: {
-//                                parent.state = "full"
-//                            }
-//                            onExited: {
-//                                parent.state = "short"
-//                            }
-//                        }
-//                    }
-//                }
-//            }
-//        }
-//    }
     FileDialog {
         id: repoOpenDialog
         folder: "."