1 #include <QTreeWidgetItem>
2 
3 #include "Data.h"
4 #include "RemoteCommitsModel.h"
5 #include "Settings.h"
6 
7 using json = nlohmann::json;
8 
RemoteCommitsModel(QObject * parent)9 RemoteCommitsModel::RemoteCommitsModel(QObject* parent) :
10     QAbstractItemModel(parent)
11 {
12     QStringList header;
13     header << tr("Commit ID") << tr("Message") << tr("Date") << tr("Author") << tr("Size");
14     rootItem = new QTreeWidgetItem(header);
15 }
16 
~RemoteCommitsModel()17 RemoteCommitsModel::~RemoteCommitsModel()
18 {
19     delete rootItem;
20 }
21 
clear()22 void RemoteCommitsModel::clear()
23 {
24     beginResetModel();
25 
26     // Remove all data except for the root item
27     while(rootItem->childCount())
28         delete rootItem->child(0);
29 
30     endResetModel();
31 }
32 
refresh(const std::string & json_data,const std::string & last_commit_id,const std::string & current_commit_id)33 void RemoteCommitsModel::refresh(const std::string& json_data, const std::string& last_commit_id, const std::string& current_commit_id)
34 {
35     // Clear previous items
36     clear();
37     beginResetModel();
38 
39     // Read in all commits
40     json j = json::parse(json_data, nullptr, false);
41     std::unordered_map<std::string, json::iterator> commit_to_iterator;
42     for(auto it=j.begin();it!=j.end();++it)
43         commit_to_iterator.insert({it.value()["id"], it});
44 
45     // Starting from the last commit add follow the chain up to the first commit
46     std::string parent_id = last_commit_id;
47     while(true)
48     {
49         if(commit_to_iterator.find(parent_id) == commit_to_iterator.end())
50             break;
51 
52         json commit = commit_to_iterator[parent_id].value();
53 
54         QTreeWidgetItem* item = new QTreeWidgetItem(rootItem);
55         item->setText(ColumnCommitId, QString::fromStdString(commit["id"]));
56         item->setText(ColumnMessage, QString::fromStdString(commit["message"]));
57         item->setToolTip(ColumnMessage, QString::fromStdString(commit["message"]));
58 
59         item->setText(ColumnDate, isoDateTimeStringToLocalDateTimeString(QString::fromStdString(commit["timestamp"])));
60 
61         QString authored_by = QString::fromStdString(commit["author_name"]) + " <" + QString::fromStdString(commit["author_email"]) + ">";
62         QString committed_by = QString::fromStdString(commit["committer_name"]) + " <" + QString::fromStdString(commit["committer_email"]) + ">";
63         item->setText(ColumnAuthor, authored_by);
64         if(committed_by == " <>" || authored_by == committed_by)    // The first check effectively checks for no committer details
65             item->setToolTip(ColumnAuthor, tr("Authored and committed by %1").arg(authored_by));
66         else
67             item->setToolTip(ColumnAuthor, tr("Authored by %1, committed by %2").arg(authored_by, committed_by));
68 
69         for(const auto& e : commit["tree"]["entries"])
70         {
71             if(e["entry_type"] == "db")
72             {
73                 item->setText(ColumnSize, humanReadableSize(e["size"]));
74                 break;
75             }
76         }
77 
78         // Make the currently checked out commit id bold
79         if(current_commit_id == commit["id"])
80         {
81             QFont bold_font = item->font(ColumnCommitId);
82             bold_font.setBold(true);
83             item->setFont(0, bold_font);
84         }
85 
86         parent_id = commit["parent"];
87     }
88 
89     // Refresh the view
90     endResetModel();
91 }
92 
index(int row,int column,const QModelIndex & parent) const93 QModelIndex RemoteCommitsModel::index(int row, int column, const QModelIndex& parent) const
94 {
95     if(!hasIndex(row, column, parent))
96         return QModelIndex();
97 
98     QTreeWidgetItem *parentItem;
99     if(!parent.isValid())
100         parentItem = rootItem;
101     else
102         parentItem = static_cast<QTreeWidgetItem*>(parent.internalPointer());
103 
104     QTreeWidgetItem* childItem = parentItem->child(row);
105     if(childItem)
106         return createIndex(row, column, childItem);
107     else
108         return QModelIndex();
109 }
110 
parent(const QModelIndex & index) const111 QModelIndex RemoteCommitsModel::parent(const QModelIndex& index) const
112 {
113     if(!index.isValid())
114         return QModelIndex();
115 
116     QTreeWidgetItem* childItem = static_cast<QTreeWidgetItem*>(index.internalPointer());
117     QTreeWidgetItem* parentItem = childItem->parent();
118 
119     if(parentItem == rootItem)
120         return QModelIndex();
121     else
122         return createIndex(0, 0, parentItem);
123 }
124 
data(const QModelIndex & index,int role) const125 QVariant RemoteCommitsModel::data(const QModelIndex& index, int role) const
126 {
127     if(!index.isValid())
128         return QVariant();
129 
130     // Get the item the index points at
131     QTreeWidgetItem* item = static_cast<QTreeWidgetItem*>(index.internalPointer());
132 
133     // Return data depending on the role
134     switch(role)
135     {
136     case Qt::DisplayRole:
137     case Qt::EditRole:
138         return item->text(index.column());
139     case Qt::ToolTipRole:
140         return item->toolTip(index.column());
141     case Qt::FontRole:
142         return item->font(0);   // Choose font for the entire row depending on the first column
143     default:
144         return QVariant();
145     }
146 }
147 
headerData(int section,Qt::Orientation orientation,int role) const148 QVariant RemoteCommitsModel::headerData(int section, Qt::Orientation orientation, int role) const
149 {
150     // Get the header string from the root item
151     if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
152         return rootItem->data(section, role);
153 
154     return QVariant();
155 }
156 
rowCount(const QModelIndex & parent) const157 int RemoteCommitsModel::rowCount(const QModelIndex& parent) const
158 {
159     if(parent.column() > 0)
160         return 0;
161 
162     if(!parent.isValid())
163         return rootItem->childCount();
164     else
165         return static_cast<QTreeWidgetItem*>(parent.internalPointer())->childCount();
166 }
167 
columnCount(const QModelIndex &) const168 int RemoteCommitsModel::columnCount(const QModelIndex& /*parent*/) const
169 {
170     return rootItem->columnCount();
171 }
172