Browse Source

Added commits oids and branches ideology
TBD: some bug with OID's copying

Alexey Edelev 10 năm trước cách đây
mục cha
commit
70273052af
22 tập tin đã thay đổi với 488 bổ sung và 226 xóa
  1. 12 7
      NiceGit.pro
  2. 34 0
      commitmodel.cpp
  3. 26 0
      commitmodel.h
  4. 5 3
      gitbase.h
  5. 9 8
      gitbranch.cpp
  6. 18 9
      gitbranch.h
  7. 85 0
      gitcommit.cpp
  8. 49 0
      gitcommit.h
  9. 19 1
      githandler.cpp
  10. 5 1
      githandler.h
  11. 41 2
      gitoid.cpp
  12. 25 3
      gitoid.h
  13. 0 6
      gitreflog.cpp
  14. 0 16
      gitreflog.h
  15. 18 62
      gitrepository.cpp
  16. 13 2
      gitrepository.h
  17. 6 0
      main.cpp
  18. 19 1
      qml/MainView.qml
  19. 1 82
      repositorymodel.cpp
  20. 4 23
      repositorymodel.h
  21. 1 0
      universallistmodel.cpp
  22. 98 0
      universallistmodel.h

+ 12 - 7
NiceGit.pro

@@ -9,24 +9,29 @@ SOURCES += \
     githandler.cpp \
     githandler.cpp \
     gitrepository.cpp \
     gitrepository.cpp \
     repositorymodel.cpp \
     repositorymodel.cpp \
-    gitreflog.cpp \
     gitbranch.cpp \
     gitbranch.cpp \
     gitreference.cpp \
     gitreference.cpp \
     gitbase.cpp \
     gitbase.cpp \
-    gitoid.cpp
+    gitoid.cpp \
+    gitcommit.cpp \
+    commitmodel.cpp \
+    universallistmodel.cpp
 
 
 HEADERS += \
 HEADERS += \
     githandler.h \
     githandler.h \
     gitrepository.h \
     gitrepository.h \
     repositorymodel.h \
     repositorymodel.h \
-    gitreflog.h \
     gitbranch.h \
     gitbranch.h \
     gitreference.h \
     gitreference.h \
     gitbase.h \
     gitbase.h \
-    gitoid.h
-
-DISTFILES += \
-    qml/MainView.qml
+    gitoid.h \
+    gitcommit.h \
+    commitmodel.h \
+    universallistmodel.h
 
 
 RESOURCES += \
 RESOURCES += \
     resources.qrc
     resources.qrc
+
+debug {
+    DEFINES += DEBUG
+}

+ 34 - 0
commitmodel.cpp

@@ -0,0 +1,34 @@
+#include "commitmodel.h"
+
+#include <gitbranch.h>
+#include <git2/revwalk.h>
+
+CommitModel::CommitModel(const QString &head, QObject* parent) : UniversalListModel(parent)
+  ,m_head(head)
+{
+}
+
+CommitModel* CommitModel::fromBranch(GitBranch* branch)
+{
+    CommitModel* tmpModel = new CommitModel(branch->name(), branch);
+    git_revwalk* walk;
+    git_revwalk_new(&walk, branch->repository()->raw());
+
+    git_revwalk_push(walk, branch->oid().raw());
+    git_revwalk_sorting(walk, GIT_SORT_TIME);
+
+    git_oid newOid;
+    while(git_revwalk_next(&newOid, walk) == 0)
+    {
+        GitOid commitOid(&newOid, branch->repository());
+        if(!tmpModel->m_container.isEmpty()) {
+            qDebug() << "Last:" << tmpModel->m_container.last().data()->sha1();
+        }
+        GitCommit *commit = GitCommit::fromOid(commitOid);
+        qDebug() << commit->sha1();
+        tmpModel->add(commit);
+    }
+
+    git_revwalk_free(walk);
+    return tmpModel;
+}

+ 26 - 0
commitmodel.h

@@ -0,0 +1,26 @@
+#ifndef COMMITMODEL_H
+#define COMMITMODEL_H
+
+#include <universallistmodel.h>
+#include <gitcommit.h>
+
+//GitBranch;
+
+class CommitModel : public UniversalListModel<GitCommit>
+{
+    Q_OBJECT
+    Q_PROPERTY(QString head READ head CONSTANT)
+public:
+    CommitModel(const QString& head, QObject* parent = 0);
+
+    static CommitModel* fromBranch(GitBranch* branch);
+    QString head() const
+    {
+        return m_head;
+    }
+
+private:
+    QString m_head;
+};
+
+#endif // COMMITMODEL_H

+ 5 - 3
gitbase.h

@@ -2,6 +2,7 @@
 #define GITBASE_H
 #define GITBASE_H
 
 
 #include <gitrepository.h>
 #include <gitrepository.h>
+#include <gitoid.h>
 
 
 #include <QObject>
 #include <QObject>
 #include <git2/types.h>
 #include <git2/types.h>
@@ -16,6 +17,7 @@ public:
     GitBase(T* raw, GitRepository* parent) : QObject(parent)
     GitBase(T* raw, GitRepository* parent) : QObject(parent)
       ,m_raw(raw)
       ,m_raw(raw)
       ,m_repository(parent)
       ,m_repository(parent)
+      ,m_oid(nullptr, parent)
     {}
     {}
 
 
     T* raw() const {
     T* raw() const {
@@ -30,14 +32,14 @@ public:
         return m_repository;
         return m_repository;
     }
     }
 
 
-    git_oid* oid() const {
-        return &m_oid;
+    const GitOid& oid() const {
+        return m_oid;
     }
     }
 
 
 protected:
 protected:
     T* m_raw;
     T* m_raw;
     GitRepository* m_repository;
     GitRepository* m_repository;
-    git_oid m_oid;
+    GitOid m_oid;
 };
 };
 
 
 #endif // GITBASE_H
 #endif // GITBASE_H

+ 9 - 8
gitbranch.cpp

@@ -5,20 +5,16 @@
 
 
 #include <git2.h>
 #include <git2.h>
 
 
-GitBranch::GitBranch(git_reference *ref, GitRepository *parent) : GitReference(ref, parent)
+GitBranch::GitBranch(git_reference *ref, git_branch_t type, GitRepository *parent) : GitReference(ref, parent)
   ,m_commit(nullptr)
   ,m_commit(nullptr)
+  ,m_type(static_cast<BranchType>(type))
 {
 {
-    char oid_buf[GIT_OID_HEXSZ+1];
     const char* tmpName;
     const char* tmpName;
     git_branch_name(&tmpName, m_raw);
     git_branch_name(&tmpName, m_raw);
     m_name = tmpName;
     m_name = tmpName;
     git_annotated_commit_from_ref(&m_commit, repository()->raw(), m_raw);
     git_annotated_commit_from_ref(&m_commit, repository()->raw(), m_raw);
-    const git_oid* tmpOid = git_annotated_commit_id(m_commit);
-    memcpy(m_oid, tmpOid, sizeof(m_oid));
-    git_oid_tostr(oid_buf, GIT_OID_HEXSZ+1,branch_oid);
-    qDebug() << oid_buf;
-    //        m_branches.insert(out)
-
+    m_oid = GitOid(git_annotated_commit_id(m_commit), m_repository);
+    qDebug() << m_oid.toString();
 }
 }
 
 
 GitBranch::~GitBranch()
 GitBranch::~GitBranch()
@@ -27,3 +23,8 @@ GitBranch::~GitBranch()
         git_annotated_commit_free(m_commit);
         git_annotated_commit_free(m_commit);
     }
     }
 }
 }
+
+GitBranch::BranchType GitBranch::type() const
+{
+    return m_type;
+}

+ 18 - 9
gitbranch.h

@@ -2,27 +2,35 @@
 #define GITBRANCH_H
 #define GITBRANCH_H
 
 
 #include <gitreference.h>
 #include <gitreference.h>
+#include <git2/types.h>
 
 
 struct git_oid;
 struct git_oid;
 
 
+class CommitModel;
+
 class GitBranch : public GitReference
 class GitBranch : public GitReference
 {
 {
     Q_OBJECT
     Q_OBJECT
     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
-
+    Q_PROPERTY(BranchType type READ type CONSTANT)
+    Q_ENUMS(BranchType)
 public:
 public:
-    GitBranch(git_reference* ref, GitRepository* parent);
+    enum BranchType {
+        Local = GIT_BRANCH_LOCAL,
+        Remote = GIT_BRANCH_REMOTE
+    };
+
+    GitBranch(git_reference* ref, git_branch_t type, GitRepository* parent);
+    virtual ~GitBranch();
 
 
-    QString name() const
-    {
+
+    QString name() const {
         return m_name;
         return m_name;
     }
     }
-
-    virtual ~GitBranch();
+    BranchType type() const;
 
 
 public slots:
 public slots:
-    void setName(QString name)
-    {
+    void setName(QString name) {
         if (m_name == name)
         if (m_name == name)
             return;
             return;
 
 
@@ -32,6 +40,7 @@ public slots:
 
 
 signals:
 signals:
     void nameChanged(QString name);
     void nameChanged(QString name);
+    void commitsChanged(CommitModel* commits);
 
 
 private:
 private:
     void free();
     void free();
@@ -40,7 +49,7 @@ private:
     QString m_name;
     QString m_name;
 
 
     git_annotated_commit* m_commit;
     git_annotated_commit* m_commit;
-    git_oid* m_oid;
+    BranchType m_type;
 };
 };
 
 
 #endif // GITBRANCH_H
 #endif // GITBRANCH_H

+ 85 - 0
gitcommit.cpp

@@ -0,0 +1,85 @@
+#include "gitcommit.h"
+
+#include <gitoid.h>
+
+#include <QDebug>
+
+#include <git2/commit.h>
+
+
+GitCommit::GitCommit(git_commit* raw, GitRepository* parent) : GitBase(raw, parent)
+{
+    m_oid = GitOid(git_commit_id(m_raw), m_repository);
+}
+
+GitCommit::GitCommit() : GitBase(nullptr, nullptr)
+{
+}
+
+GitCommit* GitCommit::fromOid(const GitOid& oid)
+{
+    if(!oid.isValid()) {
+        return nullptr;
+    }
+
+    git_commit *commit;
+    if(git_commit_lookup(&commit, oid.repository()->raw(), oid.raw()) != 0) {
+        return nullptr;
+    }
+
+    return new GitCommit(commit, oid.repository());
+}
+
+GitCommit::~GitCommit()
+{
+    git_commit_free(m_raw);
+}
+
+QString GitCommit::author() const
+{
+    return QString(git_commit_author(m_raw)->name);
+}
+
+QDateTime GitCommit::time() const
+{
+    return QDateTime::fromMSecsSinceEpoch(git_commit_time(m_raw));
+}
+
+QString GitCommit::message() const
+{
+    return QString(git_commit_message(m_raw));
+}
+
+QString GitCommit::email() const
+{
+    return QString(git_commit_author(m_raw)->email);
+}
+
+QString GitCommit::sha1() const
+{
+    return oid().toString();
+}
+
+void GitCommit::setAuthor(QString author)
+{
+    Q_UNUSED(author)
+    //TODO
+}
+
+void GitCommit::setTime(QDateTime time)
+{
+    Q_UNUSED(time)
+    //TODO
+}
+
+void GitCommit::setMessage(QString message)
+{
+    Q_UNUSED(message)
+    //TODO
+}
+
+void GitCommit::setEmail(QString email)
+{
+    Q_UNUSED(email)
+    //TODO
+}

+ 49 - 0
gitcommit.h

@@ -0,0 +1,49 @@
+#ifndef GITCOMMIT_H
+#define GITCOMMIT_H
+
+#include <gitbase.h>
+
+#include <QDateTime>
+#include <QString>
+
+#include <git2/types.h>
+
+class GitCommit : public GitBase<git_commit>
+{
+    Q_OBJECT
+    Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY commitChanged)
+    Q_PROPERTY(QString email READ email WRITE setEmail NOTIFY commitChanged)
+    Q_PROPERTY(QDateTime time READ time WRITE setTime NOTIFY commitChanged)
+    Q_PROPERTY(QString message READ message WRITE setMessage NOTIFY commitChanged)
+    Q_PROPERTY(QString sha1 READ sha1 NOTIFY commitChanged)
+
+public:
+    GitCommit(git_commit* raw, GitRepository* parent);
+    ~GitCommit();
+
+    static GitCommit* fromOid(const GitOid& oid);
+
+    QString author() const;
+    QDateTime time() const;
+    QString message() const;
+    QString email() const;
+    QString sha1() const;
+
+public slots:
+    void setAuthor(QString author);
+    void setTime(QDateTime time);
+    void setMessage(QString message);
+    void setEmail(QString email);
+
+signals:
+    void commitChanged();
+
+private:
+    GitCommit();
+    QString m_author;
+    QDateTime m_time;
+    QString m_message;
+    QString m_email;
+};
+
+#endif // GITCOMMIT_H

+ 19 - 1
githandler.cpp

@@ -5,6 +5,8 @@
 #include <qqml.h>
 #include <qqml.h>
 
 
 #include <gitrepository.h>
 #include <gitrepository.h>
+#include <gitbranch.h>
+#include <commitmodel.h>
 #include <git2.h>
 #include <git2.h>
 
 
 GitHandler::GitHandler() : QObject()
 GitHandler::GitHandler() : QObject()
@@ -39,9 +41,25 @@ void GitHandler::open(const QString &path)
         return;
         return;
     }
     }
 
 
-    m_repositories->addRepository(repo);
+    BranchContainer &branches = repo->branches();
+
+//    foreach(GitBranch* branch, branches) {
+//        qDebug() << "Branch: " << branch->name();
+//        CommitModel* model = CommitModel::fromBranch(branch);
+//        m_commits.insert(model->head(), model);
+//    }
+
+    CommitModel* model = CommitModel::fromBranch(branches.value("master"));
+    m_commits.insert(model->head(), model);
+    m_repositories->add(repo);
+}
+
+CommitModel* GitHandler::modelByHead(const QString& head)
+{
+    return m_commits.value(head).data();
 }
 }
 
 
+
 QString GitHandler::lastError() const
 QString GitHandler::lastError() const
 {
 {
     const git_error *e = giterr_last();
     const git_error *e = giterr_last();

+ 5 - 1
githandler.h

@@ -5,6 +5,9 @@
 
 
 #include <repositorymodel.h>
 #include <repositorymodel.h>
 
 
+class CommitModel;
+typedef QHash<QString, QPointer<CommitModel>> CommitModelContainer;
+
 class GitHandler : public QObject
 class GitHandler : public QObject
 {
 {
     Q_OBJECT
     Q_OBJECT
@@ -21,7 +24,7 @@ public:
         return m_repositories;
         return m_repositories;
     }
     }
 
 
-public slots:
+    Q_INVOKABLE CommitModel* modelByHead(const QString& head);
 
 
 signals:
 signals:
     void repositoriesChanged(RepositoryModel* repositories);
     void repositoriesChanged(RepositoryModel* repositories);
@@ -31,6 +34,7 @@ protected:
 
 
 private:
 private:
     RepositoryModel* m_repositories;
     RepositoryModel* m_repositories;
+    CommitModelContainer m_commits;
 };
 };
 
 
 #endif // GITHANDLER_H
 #endif // GITHANDLER_H

+ 41 - 2
gitoid.cpp

@@ -1,11 +1,50 @@
 #include "gitoid.h"
 #include "gitoid.h"
 
 
-GitOid::GitOid(const git_oid *oid, QObject *parent) : QObject(parent)
+#include <gitrepository.h>
+
+GitOid::GitOid(const git_oid *oid, GitRepository *parent) : QObject(parent)
+  ,m_oid({0})
+  ,m_repository(parent)
+{
+    updateOid(oid);
+}
+
+GitOid::GitOid(const GitOid& other) : QObject()
+{
+    updateOid(&(other.m_oid));
+    m_repository = other.m_repository;
+}
+
+const QLatin1String& GitOid::toString() const
 {
 {
+    return m_string;
+}
 
 
+bool GitOid::operator ==(const GitOid& other) const
+{
+    return git_oid_equal(&m_oid, &(other.m_oid)) == 0
+            && m_repository == other.m_repository;
 }
 }
 
 
-QString GitOid::toString() const
+GitOid& GitOid::operator=(const GitOid& other)
 {
 {
+    updateOid(&(other.m_oid));
+    m_repository = other.m_repository;
+    return *this;
+}
 
 
+void GitOid::updateOid(const git_oid* oid)
+{
+    if(oid != nullptr) {
+        git_oid_cpy(&m_oid, oid);
+        m_string = QLatin1String(git_oid_tostr_s(&m_oid));
+    } else {
+        memset(&m_oid, 0, sizeof(m_oid));
+        m_string = QLatin1String("");
+    }
+}
+
+bool GitOid::isValid() const
+{
+    return !git_oid_iszero(&m_oid) && m_repository != nullptr;
 }
 }

+ 25 - 3
gitoid.h

@@ -4,15 +4,37 @@
 #include <QObject>
 #include <QObject>
 #include <git2/oid.h>
 #include <git2/oid.h>
 
 
+class GitRepository;
+
 class GitOid : public QObject
 class GitOid : public QObject
 {
 {
     Q_OBJECT
     Q_OBJECT
 public:
 public:
-    explicit GitOid(const git_oid* oid = 0, QObject *parent = 0);
-    QString toString() const;
+    GitOid(const git_oid* oid, GitRepository *parent);
+    GitOid(const GitOid& other);
+
+
+    bool operator ==(const GitOid& other) const;
+    GitOid& operator=(const GitOid& other);
+
+    const git_oid* raw() const {
+        return &m_oid;
+    }
+
+    GitRepository* repository() const {
+        return m_repository;
+    }
+
+    const QLatin1String &toString() const;
+
+    bool isValid() const;
+
 private:
 private:
+    void updateOid(const git_oid* oid);
+
     git_oid m_oid;
     git_oid m_oid;
-    bool isValid;
+    QLatin1String m_string;
+    GitRepository *m_repository;
 };
 };
 
 
 #endif // GITOID_H
 #endif // GITOID_H

+ 0 - 6
gitreflog.cpp

@@ -1,6 +0,0 @@
-#include "gitreflog.h"
-
-GitReflog::GitReflog(GitRepository *repo)
-{
-
-}

+ 0 - 16
gitreflog.h

@@ -1,16 +0,0 @@
-#ifndef GITREFLOG_H
-#define GITREFLOG_H
-
-struct git_reflog;
-
-class GitRepository;
-
-class GitReflog
-{
-public:
-    GitReflog(GitRepository* repo);
-private:
-    git_reflog* m_reflog;
-};
-
-#endif // GITREFLOG_H

+ 18 - 62
gitrepository.cpp

@@ -5,11 +5,10 @@
 #include <QDir>
 #include <QDir>
 
 
 #include <gitbranch.h>
 #include <gitbranch.h>
+#include <gitcommit.h>
 
 
 #include <git2.h>
 #include <git2.h>
 
 
-char oid_buf[GIT_OID_HEXSZ+1];
-
 GitRepository::GitRepository(const QString& root) : QObject(nullptr)
 GitRepository::GitRepository(const QString& root) : QObject(nullptr)
 {
 {
     if(git_repository_open(&m_raw, root.toUtf8().data()) != 0) {
     if(git_repository_open(&m_raw, root.toUtf8().data()) != 0) {
@@ -22,66 +21,7 @@ GitRepository::GitRepository(const QString& root) : QObject(nullptr)
     m_path = git_repository_workdir(m_raw);
     m_path = git_repository_workdir(m_raw);
     m_name = m_path;//TODO: replace with Human readable name
     m_name = m_path;//TODO: replace with Human readable name
     qDebug() << "New repo:" << m_name << m_root << m_path;
     qDebug() << "New repo:" << m_name << m_root << m_path;
-
-    //    git_reflog* reflog;
-
-    //    if(git_reflog_read(&reflog, m_raw, "HEAD") != 0) {
-    //        qDebug() << "reflogs could not be read";
-    //        return;
-    //    }
-
-    //    quint64 count = git_reflog_entrycount(reflog);
-    //    qDebug() << count;
-
-    //    for(quint64 i = 0; i < count; i++)
-    //    {
-    //        git_reflog_entry* entry = git_reflog_entry_byindex(reflog, i);
-    //        git_oid* oid = git_reflog_entry_id_new(entry);
-    //    }
-    //    git_reflog_free(reflog);
-
-    git_reference *out;
-    git_branch_t branch;
-    git_branch_iterator* iter;
-    git_branch_iterator_new(&iter, m_raw, GIT_BRANCH_ALL);
-
-    git_revwalk* walk;
-    git_revwalk_new(&walk, m_raw);
-    qDebug() << "Branches found:";
-    while(git_branch_next(&out, &branch, iter) == 0)
-    {
-        GitBranch testBranch(out, this);
-        qDebug() << testBranch.name();
-    }
-
-    return;
-
-    git_revwalk_push_glob(walk, "refs/heads/*");
-    git_revwalk_sorting(walk, GIT_SORT_TIME);
-
-    git_oid newoid;
-    while(git_revwalk_next(&newoid, walk) == 0)
-    {
-        git_commit *wcommit;
-        if(git_commit_lookup(&wcommit, m_raw, &newoid) != 0 )
-        {
-            qDebug() << "git_commit_lookup error";
-            continue;
-        }
-
-        const git_oid* commit_oid = git_commit_id(wcommit);
-        git_oid_tostr(oid_buf,GIT_OID_HEXSZ+1,commit_oid);
-        qDebug() << oid_buf;
-        qDebug() << git_commit_time( wcommit );
-        qDebug() << git_commit_message( wcommit );
-        qDebug() << git_commit_author( wcommit );
-
-        qDebug() << "=================================================";
-        git_commit_free( wcommit );
-    }
-
-    git_revwalk_free( walk );
-
+    readBranches();
 }
 }
 
 
 GitRepository::~GitRepository()
 GitRepository::~GitRepository()
@@ -96,3 +36,19 @@ void GitRepository::close()
     }
     }
     m_raw = nullptr;
     m_raw = nullptr;
 }
 }
+
+void GitRepository::readBranches()
+{
+    git_reference *branchRef;
+    git_branch_t branchType;
+    git_branch_iterator* iter;
+    git_branch_iterator_new(&iter, m_raw, GIT_BRANCH_ALL);
+    while(git_branch_next(&branchRef, &branchType, iter) == 0)
+    {
+        GitBranch* branch = new GitBranch(branchRef, branchType, this);
+        m_branches.insert(branch->name(), QPointer<GitBranch>(branch));
+        qDebug() << branch->name();
+        qDebug() << branch->type();
+    }
+}
+

+ 13 - 2
gitrepository.h

@@ -3,9 +3,13 @@
 
 
 #include <QObject>
 #include <QObject>
 #include <QString>
 #include <QString>
+#include <QHash>
+#include <QPointer>
 
 
 struct git_repository;
 struct git_repository;
 
 
+class GitBranch;
+typedef QHash<QString, QPointer<GitBranch>> BranchContainer;
 
 
 class GitRepository : public QObject
 class GitRepository : public QObject
 {
 {
@@ -13,6 +17,7 @@ class GitRepository : public QObject
     Q_PROPERTY(QString root READ root WRITE setRoot NOTIFY rootChanged)
     Q_PROPERTY(QString root READ root WRITE setRoot NOTIFY rootChanged)
     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
     Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
     Q_PROPERTY(QString path READ path NOTIFY rootChanged)
     Q_PROPERTY(QString path READ path NOTIFY rootChanged)
+
 public:
 public:
     GitRepository(const QString &root);
     GitRepository(const QString &root);
     ~GitRepository();
     ~GitRepository();
@@ -25,8 +30,7 @@ public:
         return m_name;
         return m_name;
     }
     }
 
 
-    QString path() const
-    {
+    QString path() const {
         return m_path;
         return m_path;
     }
     }
 
 
@@ -38,6 +42,10 @@ public:
         return m_raw != nullptr;
         return m_raw != nullptr;
     }
     }
 
 
+    BranchContainer& branches() {
+        return m_branches;
+    }
+
 
 
 public slots:
 public slots:
     void setRoot(QString root) {
     void setRoot(QString root) {
@@ -62,11 +70,14 @@ signals:
 
 
 private:
 private:
     void close();
     void close();
+    void readBranches();
 
 
     QString m_root;
     QString m_root;
     QString m_name;
     QString m_name;
     QString m_path;
     QString m_path;
     git_repository* m_raw;
     git_repository* m_raw;
+
+    BranchContainer m_branches;
 };
 };
 
 
 #endif // GITREPOSITORY_H
 #endif // GITREPOSITORY_H

+ 6 - 0
main.cpp

@@ -6,6 +6,8 @@
 #include <githandler.h>
 #include <githandler.h>
 #include <gitrepository.h>
 #include <gitrepository.h>
 #include <repositorymodel.h>
 #include <repositorymodel.h>
+#include <gitbranch.h>
+#include <commitmodel.h>
 
 
 #include <QDebug>
 #include <QDebug>
 
 
@@ -17,12 +19,16 @@ int main(int argc, char *argv[])
 
 
     qmlRegisterUncreatableType<GitHandler>("org.semlanik.nicegit", 1, 0, "GitHandler", "Global for qml");
     qmlRegisterUncreatableType<GitHandler>("org.semlanik.nicegit", 1, 0, "GitHandler", "Global for qml");
     qmlRegisterUncreatableType<GitRepository>("org.semlanik.nicegit", 1, 0, "GitRepository", "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<RepositoryModel>("org.semlanik.nicegit", 1, 0, "RepositoryModel", "Owned only by GitHandler");
+    qmlRegisterUncreatableType<CommitModel>("org.semlanik.nicegit", 1, 0, "CommitModel", "Owned only by GitHandler");
+
 
 
     GitHandler handler;
     GitHandler handler;
     handler.open("/home/semlanik/Projects/testrepo/");
     handler.open("/home/semlanik/Projects/testrepo/");
     view.rootContext()->setContextProperty("_handler", &handler);
     view.rootContext()->setContextProperty("_handler", &handler);
     view.setSource(QUrl("qrc:/qml/MainView.qml"));
     view.setSource(QUrl("qrc:/qml/MainView.qml"));
+    view.setResizeMode(QQuickView::SizeRootObjectToView);
     view.showMaximized();
     view.showMaximized();
     return app.exec();
     return app.exec();
 }
 }

+ 19 - 1
qml/MainView.qml

@@ -1,6 +1,7 @@
 import QtQuick 2.0
 import QtQuick 2.0
 import QtQuick.Controls 1.4
 import QtQuick.Controls 1.4
 import QtQuick.Dialogs 1.2
 import QtQuick.Dialogs 1.2
+import org.semlanik.nicegit 1.0
 
 
 Item {
 Item {
     Row {
     Row {
@@ -20,7 +21,24 @@ Item {
             model: _handler.repositories
             model: _handler.repositories
 
 
             Text {
             Text {
-                text: model.repoName
+                text: model.name
+            }
+        }
+    }
+
+
+    ListView {
+        height: 200
+        width: 100
+        anchors.right: parent.right
+        model: _handler.modelByHead("master")
+        delegate: Rectangle {
+            color: "#cccccc"
+            width: 200
+            height: 100
+            Text {
+                anchors.centerIn: parent
+                text: model.sha1
             }
             }
         }
         }
     }
     }

+ 1 - 82
repositorymodel.cpp

@@ -1,92 +1,11 @@
 #include "repositorymodel.h"
 #include "repositorymodel.h"
-#include <gitrepository.h>
 
 
 #include <QDebug>
 #include <QDebug>
 
 
-QHash<int, QByteArray> RepositoryModel::m_roles;
-
-RepositoryModel::RepositoryModel(QObject* parent) : QAbstractListModel(parent)
+RepositoryModel::RepositoryModel(QObject* parent) : UniversalListModel(parent)
 {
 {
-    if(m_roles.isEmpty()) {
-        m_roles[RepoName] = "repoName";
-        m_roles[RepoRoot] = "repoRoot";
-        m_roles[RepoBranches] = "repoBranches";
-    }
 }
 }
 
 
 RepositoryModel::~RepositoryModel()
 RepositoryModel::~RepositoryModel()
 {
 {
-    foreach (QPointer<GitRepository> repo, m_repositories) {
-        delete repo.data();
-    }
-    m_repositories.clear();
 }
 }
-
-bool RepositoryModel::addRepository(GitRepository* repo)
-{
-    if(repo == nullptr)
-    {
-        qDebug() << "Repo is null";
-        return false;
-    }
-
-    if(m_repositories.contains(repo->root())) {
-        qDebug() << "Repository" << repo->root() << "already exists";
-        return false;
-    }
-    beginInsertRows(QModelIndex(),0,0);
-    m_repositories.insert(repo->root(), QPointer<GitRepository>(repo));
-    endInsertRows();
-    return true;
-}
-
-void RepositoryModel::removeRepository(GitRepository* repo)
-{
-    if(repo == nullptr) {
-        return;
-    }
-
-    if(m_repositories.contains(repo->root())) {
-        beginRemoveRows(QModelIndex(), m_repositories.values().indexOf(repo), m_repositories.values().indexOf(repo));
-        m_repositories.remove(repo->root());
-        endRemoveRows();
-    }
-}
-
-void RepositoryModel::removeRepository(const QString& root)
-{
-    m_repositories.remove(root);
-}
-
-QVariant RepositoryModel::data(const QModelIndex &index, int role) const
-{
-    int row = index.row();
-
-    if(row < 0 || row >= m_repositories.count()) {
-        return QVariant();
-    }
-
-    GitRepository* repo = m_repositories.values().at(row).data();
-
-    switch (role) {
-    case RepoName:
-        return QVariant(repo->name());
-    case RepoRoot:
-        return QVariant(repo->root());
-    default:
-        break;
-    }
-    return QVariant();
-}
-
-int RepositoryModel::rowCount(const QModelIndex &parent) const
-{
-    Q_UNUSED(parent)
-    return m_repositories.count();
-}
-
-QHash<int, QByteArray> RepositoryModel::roleNames() const
-{
-    return m_roles;
-}
-

+ 4 - 23
repositorymodel.h

@@ -1,37 +1,18 @@
 #ifndef REPOSITORYMODEL_H
 #ifndef REPOSITORYMODEL_H
 #define REPOSITORYMODEL_H
 #define REPOSITORYMODEL_H
 
 
-#include <QAbstractListModel>
-#include <QHash>
+#include <universallistmodel.h>
+#include <gitrepository.h>
 #include <QString>
 #include <QString>
 #include <QPointer>
 #include <QPointer>
 
 
-class GitRepository;
-
-class RepositoryModel : public QAbstractListModel
+class RepositoryModel : public UniversalListModel<GitRepository>
 {
 {
     Q_OBJECT
     Q_OBJECT
 public:
 public:
-    enum Roles {
-        RepoName,
-        RepoRoot,
-        RepoBranches
-    };
-
     RepositoryModel(QObject *parent = 0);
     RepositoryModel(QObject *parent = 0);
     ~RepositoryModel();
     ~RepositoryModel();
-
-    bool addRepository(GitRepository* repo);
-    void removeRepository(GitRepository* repo);
-    void removeRepository(const QString& root);
-
-    QVariant data(const QModelIndex &index, int role) const;
-    int rowCount(const QModelIndex &parent) const;
-    QHash<int, QByteArray> roleNames() const;
-
-private:
-    QHash<QString, QPointer<GitRepository>> m_repositories;
-    static QHash<int, QByteArray> m_roles;
 };
 };
 
 
+
 #endif // REPOSITORYMODEL_H
 #endif // REPOSITORYMODEL_H

+ 1 - 0
universallistmodel.cpp

@@ -0,0 +1 @@
+#include "universallistmodel.h"

+ 98 - 0
universallistmodel.h

@@ -0,0 +1,98 @@
+#ifndef UNIVERSALLISTMODEL_H
+#define UNIVERSALLISTMODEL_H
+
+#include <QAbstractListModel>
+
+#include <QObject>
+#include <QList>
+#include <QHash>
+#include <QPointer>
+#include <QMetaProperty>
+#include <QMetaObject>
+
+#include <QDebug>
+
+template <typename T>
+class UniversalListModel : public QAbstractListModel
+{
+public:
+    ~UniversalListModel() {
+        foreach (QPointer<T> value, m_container) {
+            delete value.data();
+        }
+        m_container.clear();
+    }
+
+    int rowCount(const QModelIndex &parent) const {
+        Q_UNUSED(parent)
+        return m_container.count();
+    }
+
+    QHash<int, QByteArray> roleNames() const {
+        if(s_roleNames.isEmpty()) {
+            int propertyCount = T::staticMetaObject.propertyCount();
+            for(int i = 0; i < propertyCount; i++) {
+                s_roleNames.insert(Qt::UserRole + i, T::staticMetaObject.property(i).name());
+            }
+        }
+        return s_roleNames;
+    }
+
+    QVariant data(const QModelIndex &index, int role) const
+    {
+        int row = index.row();
+
+        if(row < 0 || row >= m_container.count()) {
+            return QVariant();
+        }
+
+        T* dataPtr = m_container.at(row).data();
+        return dataPtr->property(s_roleNames.value(role));
+    }
+
+    bool add(T* value) {
+        Q_ASSERT_X(value != nullptr, fullTemplateName(), "Trying to add member of NULL");
+
+        if(m_container.indexOf(value) >= 0) {
+#ifdef DEBUG
+            qDebug() << fullTemplateName() << "Member already exists";
+#endif
+            return false;
+        }
+        beginInsertRows(QModelIndex(), m_container.count(), m_container.count());
+        m_container.append(QPointer<T>(value));
+        endInsertRows();
+        return true;
+    }
+
+    void remove(T* value) {
+        Q_ASSERT_X(value != nullptr, fullTemplateName(), ": Trying to remove member of NULL");
+
+        int valueIndex = m_container.indexOf(value);
+
+        if(valueIndex >= 0) {
+            beginRemoveRows(QModelIndex(), valueIndex, valueIndex);
+            m_container.removeAt(valueIndex);
+            endRemoveRows();
+        }
+    }
+
+protected:
+    UniversalListModel(QObject* parent = 0) : QAbstractListModel(parent) {}
+
+    QList<QPointer<T>> m_container;
+    static QHash<int, QByteArray> s_roleNames;
+
+
+private:
+#ifdef DEBUG
+    static QByteArray fullTemplateName() { //Debug helper
+        return QString("UniversalListModel<%1>").arg(T::staticMetaObject.className()).toLatin1();
+    }
+#endif
+};
+
+template<typename T>
+QHash<int, QByteArray> UniversalListModel<T>::s_roleNames;
+
+#endif // UNIVERSALLISTMODEL_H