Browse Source

Make graph and diffs build in QtConcurrent thread. This change unlocks main thread

Alexey Edelev 7 years ago
parent
commit
42f70fad18
7 changed files with 112 additions and 34 deletions
  1. 1 1
      NiceGit.pro
  2. 1 1
      gitbase.h
  3. 7 1
      gitdiff.cpp
  4. 56 21
      githandler.cpp
  5. 20 2
      githandler.h
  6. 1 1
      gitoid.cpp
  7. 26 7
      qml/MainView.qml

+ 1 - 1
NiceGit.pro

@@ -1,4 +1,4 @@
-QT += qml quick widgets
+QT += qml quick widgets concurrent
 
 TEMPLATE = app
 

+ 1 - 1
gitbase.h

@@ -12,7 +12,7 @@ template <typename T>
 class GitBase : public QObject
 {
 public:
-    GitBase(T* raw, GitRepository* parent) : QObject(parent)
+    GitBase(T* raw, GitRepository* parent) : QObject()
       ,m_raw(raw)
       ,m_repository(parent)
     {}

+ 7 - 1
gitdiff.cpp

@@ -49,7 +49,7 @@ GitDiff* GitDiff::diff(GitCommit* a, GitCommit* b)
     }
 
     if(!isValid) {
-        qDebug() << "Both compared commits are invalid";
+        qCritical() << "Both compared commits are invalid";
         return diff;
     }
 
@@ -59,6 +59,8 @@ GitDiff* GitDiff::diff(GitCommit* a, GitCommit* b)
 
     diff = new GitDiff(diffRaw,repo);
     diff->readBody(diffRaw);
+    diff->moveToThread(a->repository()->thread());
+    diff->setParent(a->repository());
 
     return diff;
 }
@@ -70,6 +72,7 @@ GitDiff* GitDiff::diff(GitCommit* a)
     git_tree *aTree = nullptr;
 
     if(a == nullptr) {
+        qCritical() << "Requested diff for zero-pointer commit";
         return nullptr;
     }
 
@@ -80,7 +83,10 @@ GitDiff* GitDiff::diff(GitCommit* a)
 
     diff = new GitDiff(diffRaw, a->repository());
     diff->readBody(diffRaw);
+    diff->moveToThread(a->repository()->thread());
+    diff->setParent(a->repository());
 
+    delete a;//TODO need indication if "a" could be deleted
     return diff;
 }
 

+ 56 - 21
githandler.cpp

@@ -5,6 +5,7 @@
 #include <QFileSystemWatcher>
 #include <QGuiApplication>
 #include <QClipboard>
+#include <QtConcurrentRun>
 #include <qqml.h>
 
 #include <gitrepository.h>
@@ -32,8 +33,16 @@ GitHandler::GitHandler() : QObject()
   ,m_tagList(new TagListModel(this))
   ,m_activeRepoWatcher(new QFileSystemWatcher(this))
   ,m_console(new GitConsole(this))
-{
+{    
     git_libgit2_init();
+    connect(&m_diffTask, &QFutureWatcher<GitDiff*>::finished, this, &GitHandler::onDiffReady);
+    connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::finished, this, &GitHandler::onGraphReady);
+
+    connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::started, this, &GitHandler::isBusyChanged);
+    connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::finished, this, &GitHandler::isBusyChanged);
+    connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::canceled, this, &GitHandler::isBusyChanged);
+    connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::paused, this, &GitHandler::isBusyChanged);
+    connect(&m_graphTask, &QFutureWatcher<CommitGraph*>::resumed, this, &GitHandler::isBusyChanged);
 }
 
 GitHandler::~GitHandler()
@@ -93,7 +102,7 @@ QString GitHandler::lastError() const
     return QString();
 }
 
-GitDiff* GitHandler::diff(GitCommit* a, GitCommit* b)
+void GitHandler::diff(GitCommit* a, GitCommit* b)
 {
     if(!m_activeDiff.isNull()) {
         m_activeDiff->deleteLater();
@@ -101,19 +110,35 @@ GitDiff* GitHandler::diff(GitCommit* a, GitCommit* b)
 
     Q_ASSERT_X(a->repository() == b->repository(), "GitHandler", "Cross repository diff requested");
 
-    m_activeDiff = GitDiff::diff(a, b);
-    return m_activeDiff.data();
+    if(m_diffTask.isRunning()) {
+        m_diffTask.cancel();
+    }
+
+    qDebug() << "Diff start thread: " << QThread::currentThreadId();
+    QFuture<GitDiff*> future = QtConcurrent::run(&GitDiff::diff, a, b);
+    m_diffTask.setFuture(future);
 }
 
-GitDiff* GitHandler::diff()
+void 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();
+    GitCommit* commit = GitCommit::fromOid(activeRepo()->head());
+
+    QFuture<GitDiff*> future = QtConcurrent::run(&GitDiff::diff, commit);
+    m_diffTask.setFuture(future);
+}
+
+void GitHandler::diffReset()
+{
+    delete m_activeDiff;
+}
+
+void GitHandler::onDiffReady()
+{
+    setActiveDiff(m_diffTask.result());
 }
 
 
@@ -141,9 +166,23 @@ void GitHandler::updateModels()
     if(!m_activeRepo) {
         return;
     }
+    BranchContainer &branches = m_activeRepo->branches();
     m_activeRepo->updateHead();
 
-    BranchContainer &branches = m_activeRepo->branches();
+    m_graphTask.cancel();
+    m_graphTask.setFuture(QtConcurrent::run(&GitHandler::updateGraph, m_activeRepo->head(), branches));
+
+    m_branchList->reset(branches.values());
+    m_tagList->reset(m_activeRepo->tags().values());
+}
+
+void GitHandler::copy(const QString& sha1)
+{
+    QGuiApplication::clipboard()->setText(sha1);
+}
+
+CommitGraph* GitHandler::updateGraph(const GitOid &head, const BranchContainer &branches)
+{
     CommitGraph* graph = new CommitGraph();
 
     bool headIsBranch = false;
@@ -157,7 +196,7 @@ void GitHandler::updateModels()
 //    }
 
     if(!headIsBranch) {
-        graph->addHead(m_activeRepo->head());
+        graph->addHead(head);
     }
 
     foreach(GitBranch* branch, branches) {
@@ -165,20 +204,16 @@ void GitHandler::updateModels()
         graph->addHead(branch);
     }
     graph->addWorkdir();
+    graph->moveToThread(head.repository()->thread());
+    return graph;
+}
 
+void GitHandler::onGraphReady()
+{
     m_graph->deleteLater();
-    m_graph = graph;
-    emit graphChanged(graph);
+    m_graph = m_graphTask.result();
+    emit graphChanged(m_graph);
 
     m_commits = CommitModel::fromGraph(m_graph);
     emit commitsChanged(m_commits);
-
-    m_branchList->reset(m_activeRepo->branches().values());
-    m_tagList->reset(m_activeRepo->tags().values());
-}
-
-void GitHandler::copy(const QString& sha1)
-{
-    QGuiApplication::clipboard()->setText(sha1);
 }
-

+ 20 - 2
githandler.h

@@ -4,6 +4,7 @@
 #include <QObject>
 
 #include <repositorymodel.h>
+#include <QFutureWatcher>
 
 class CommitModel;
 class CommitGraph;
@@ -25,6 +26,7 @@ class GitHandler : public QObject
     Q_PROPERTY(BranchListModel* branchList READ branchList CONSTANT)
     Q_PROPERTY(TagListModel* tagList READ tagList CONSTANT)
     Q_PROPERTY(GitConsole* console READ console CONSTANT)
+    Q_PROPERTY(bool isBusy READ isBusy NOTIFY isBusyChanged)
 
 public:
     GitHandler();
@@ -32,9 +34,11 @@ public:
     Q_INVOKABLE void open(const QString &path);
     Q_INVOKABLE void open(const QUrl &url);
 
-    Q_INVOKABLE GitDiff* diff(GitCommit* a, GitCommit* b);
+    Q_INVOKABLE void diff(GitCommit* a, GitCommit* b);
 
-    Q_INVOKABLE GitDiff* diff(); //Dif of workdir
+    Q_INVOKABLE void diff(); //Dif of workdir
+    Q_INVOKABLE void diffReset();
+    void onDiffReady();
 
     Q_INVOKABLE void copy(const QString& sha1);
 
@@ -77,6 +81,11 @@ public:
         return m_console;
     }
 
+    bool isBusy() const
+    {
+        return !m_graphTask.isCanceled() && !m_graphTask.isFinished();
+    }
+
 public slots:
     void setActiveDiff(GitDiff* activeDiff);
 
@@ -98,12 +107,17 @@ signals:
 
     void commitsChanged(CommitModel* commits);
 
+    void isBusyChanged();
+
 protected:
     QString lastError() const;
 
 private:
     void updateModels();
 
+    static CommitGraph* updateGraph(const GitOid& head, const BranchContainer &branches);
+    void onGraphReady();
+
     RepositoryModel* m_repositories;
     CommitModel* m_commits;
     CommitGraph* m_graph;
@@ -114,6 +128,10 @@ private:
     QFileSystemWatcher* m_activeRepoWatcher;
     GitConsole* m_console;
     GitOid m_constantHead;
+    QFutureWatcher<GitDiff*> m_diffTask;
+    QFutureWatcher<CommitGraph*> m_graphTask;
+
+    bool m_isBusy;
 };
 
 #endif // GITHANDLER_H

+ 1 - 1
gitoid.cpp

@@ -8,7 +8,7 @@ GitOid::GitOid() : QObject()
 {
 }
 
-GitOid::GitOid(const git_oid *oid, GitRepository *parent) : QObject(parent)
+GitOid::GitOid(const git_oid *oid, GitRepository *parent) : QObject()
   ,m_oid({0})
   ,m_repository(parent)
 {

+ 26 - 7
qml/MainView.qml

@@ -10,7 +10,7 @@ FocusScope {
     TopBar {
         id: topBar
         onCloseClicked: {
-            commitPlane.diff = null
+            _handler.diffReset()
             commitPlane.commit = null
             commitList.state = "full"
             commitList.activeCommit = null
@@ -35,14 +35,14 @@ FocusScope {
         onCommitClicked: {
             if(commit == null) {
                 commitPlane.commit = null
-                commitPlane.diff = _handler.diff()
+                _handler.diff()
                 commitList.state = "commitsOnly"
                 return;
             }
 
             if(commit.diff === null) {
                 commitPlane.commit = null
-                commitPlane.diff = null
+                _handler.diffReset()
                 commitList.state = "full"
                 return
             }
@@ -61,7 +61,7 @@ FocusScope {
                 root.commitsForDiff.push(commit)
                 if(root.commitsForDiff.length === 2) {
                     commitPlane.commit = root.commitsForDiff[1]
-                    commitPlane.diff = _handler.diff(root.commitsForDiff[0], root.commitsForDiff[1])
+                    _handler.diff(root.commitsForDiff[0], root.commitsForDiff[1])
                     root.commitsForDiff=[]
                 }
             }
@@ -74,10 +74,32 @@ FocusScope {
         anchors.right: parent.right
         anchors.top: topBar.bottom
         anchors.bottom: consoleContol.top
+        Binding {
+            target: commitPlane
+            property: "diff"
+            value: _handler.activeDiff
+        }
+
 //        visible: diff != null
 //        opacity: diff != null ? 1.0 : 0.0
     }
 
+    Rectangle {
+        id: dimmingPlane
+        anchors.fill: parent
+        MouseArea {
+            anchors.fill: parent
+        }
+        color: "black"
+        opacity: _handler.isBusy ? 0.4 : 0.0
+        visible: opacity > 0
+        Behavior on opacity {
+            NumberAnimation {
+                duration: 500
+            }
+        }
+    }
+
     ConsoleControl {
         id: consoleContol
         anchors.left: parent.left
@@ -119,7 +141,4 @@ FocusScope {
 
     Tooltip {
     }
-//    Component.onCompleted: {
-//        commitPlane.diff = _handler.diff();
-//    }
 }