1 /* This file is part of the KDE project
2  * Copyright 2014  Dan Leinir Turthra Jensen <admin@leinir.dk>
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of
7  * the License or (at your option) version 3 or any later version
8  * accepted by the membership of KDE e.V. (or its successor approved
9  * by the membership of KDE e.V.), which shall act as a proxy
10  * defined in Section 14 of version 3 of the license.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 #include "gitlogmodel.h"
23 
24 // #include <qgit2.h>
25 // #include <qgit2/qgitglobal.h>
26 
27 #include <git2.h>
28 #include <git2/repository.h>
29 
30 #include <QDateTime>
31 #include <QDebug>
32 
33 struct LogEntry {
34 public:
LogEntryLogEntry35     LogEntry() {}
36     QString authorName;
37     QString authorEmail;
38     QDateTime time;
39     QString oid;
40     QString shortMessage;
41     QString message;
42 };
43 
44 class GitLogModel::Private
45 {
46 public:
Private()47     Private() {}
~Private()48     ~Private()
49     {
50         qDeleteAll(entries);
51     }
52     QString repoDir;
53     QList<LogEntry*> entries;
54 };
55 
GitLogModel(QObject * parent)56 GitLogModel::GitLogModel(QObject* parent)
57     : QAbstractListModel(parent)
58     , d(new Private)
59 {
60     QHash<int, QByteArray> roleNames;
61     roleNames[AuthorNameRole] = "authorName";
62     roleNames[AuthorEmailRole] = "authorEmail";
63     roleNames[TimeRole] = "time";
64     roleNames[OIDRole] = "oid";
65     roleNames[ShortMessageRole] = "shortMessage";
66     roleNames[MessageRole] = "message";
67     setRoleNames(roleNames);
68 }
69 
~GitLogModel()70 GitLogModel::~GitLogModel()
71 {
72     delete d;
73 }
74 
rowCount(const QModelIndex & parent) const75 int GitLogModel::rowCount(const QModelIndex &parent) const
76 {
77     if ( parent.isValid() )
78         return 0;
79     return d->entries.count();
80 }
81 
data(const QModelIndex & index,int role) const82 QVariant GitLogModel::data(const QModelIndex &index, int role) const
83 {
84     QVariant data;
85     if(index.isValid() && index.row() < d->entries.count()) {
86         LogEntry * entry = d->entries.at(index.row());
87         switch(role)
88         {
89             case AuthorNameRole:
90                 data = entry->authorName;
91                 break;
92             case AuthorEmailRole:
93                 data = entry->authorEmail;
94                 break;
95             case TimeRole:
96                 data = entry->time;
97                 break;
98             case OIDRole:
99                 data = entry->oid;
100                 break;
101             case ShortMessageRole:
102                 data = entry->shortMessage;
103                 break;
104             case MessageRole:
105                 data = entry->message;
106                 break;
107             default:
108                 data = "Unknown Role";
109                 break;
110         }
111     }
112     return data;
113 }
114 
repoDir() const115 QString GitLogModel::repoDir() const
116 {
117     return d->repoDir;
118 }
119 
setRepoDir(const QString & repoDir)120 void GitLogModel::setRepoDir(const QString& repoDir)
121 {
122     if(d->repoDir != repoDir) {
123         d->repoDir = repoDir;
124         refreshLog();
125         emit repoDirChanged();
126     }
127 }
128 
refreshLog()129 void GitLogModel::refreshLog()
130 {
131     beginResetModel();
132     qDeleteAll(d->entries);
133     d->entries.clear();
134 
135     git_repository* repository;
136     int error = git_repository_open(&repository, QString("%1/.git").arg(d->repoDir).toLatin1());
137     if(error != 0) { const git_error* err = giterr_last(); qDebug() << "Kapow, error code from git2 was" << error << "which is described as" << err->message; return; }
138 
139     git_revwalk *walker;
140     error = git_revwalk_new(&walker, repository);
141     if(error != 0) { const git_error* err = giterr_last(); qDebug() << "Kapow, error code from git2 was" << error << "which is described as" << err->message; return; }
142     error = git_revwalk_push_range(walker, "HEAD~100..HEAD");
143     if(error != 0) { const git_error* err = giterr_last(); qDebug() << "Kapow, error code from git2 was" << error << "which is described as" << err->message; return; }
144 
145     git_oid oid;
146     git_commit *commit = NULL;
147     while (git_revwalk_next(&oid, walker) == 0) {
148         error = git_commit_lookup(&commit, repository, &oid);
149         if(error != 0) { const git_error* err = giterr_last(); qDebug() << "Kapow, error code from git2 was" << error << "which is described as" << err->message; return; }
150 
151         const git_signature *author = git_commit_author(commit);
152 
153         LogEntry* entry = new LogEntry();
154         entry->authorName = author->name;
155         if(entry->authorName.isEmpty())
156             entry->authorName = "Unknown";
157         entry->authorEmail = author->email;
158 
159         git_time_t time = git_commit_time(commit);
160         entry->time = QDateTime::fromMSecsSinceEpoch(time * 1000);
161 
162         entry->oid = QString::fromAscii(git_oid_tostr_s(git_commit_id(commit)));
163         entry->message = QString::fromAscii(git_commit_message(commit));
164         entry->shortMessage = entry->message.left(120).split(QRegExp("(\\r|\\n)")).first();
165 
166         d->entries.append(entry);
167 
168         git_commit_free(commit);
169     }
170     git_repository_free(repository);
171     endResetModel();
172 }
173