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