1 | #include "CommitHistoryView.h" |
2 | |
3 | #include <CommitHistoryColumns.h> |
4 | #include <CommitHistoryContextMenu.h> |
5 | #include <CommitHistoryModel.h> |
6 | #include <CommitInfo.h> |
7 | #include <GitBase.h> |
8 | #include <GitCache.h> |
9 | #include <GitConfig.h> |
10 | #include <GitQlientSettings.h> |
11 | #include <ShaFilterProxyModel.h> |
12 | |
13 | #include <QDateTime> |
14 | #include <QHeaderView> |
15 | |
16 | #include <QLogger.h> |
17 | using namespace QLogger; |
18 | |
19 | CommitHistoryView::CommitHistoryView(const QSharedPointer<GitCache> &cache, const QSharedPointer<GitBase> &git, |
20 | const QSharedPointer<GitQlientSettings> &settings, |
21 | const QSharedPointer<GitServerCache> &gitServerCache, QWidget *parent) |
22 | : QTreeView(parent) |
23 | , mCache(cache) |
24 | , mGit(git) |
25 | , mSettings(settings) |
26 | , mGitServerCache(gitServerCache) |
27 | { |
28 | setEnabled(false); |
29 | setContextMenuPolicy(Qt::CustomContextMenu); |
30 | setItemsExpandable(false); |
31 | setMouseTracking(true); |
32 | setSelectionMode(QAbstractItemView::ExtendedSelection); |
33 | setAttribute(Qt::WA_DeleteOnClose); |
34 | |
35 | header()->setSortIndicatorShown(false); |
36 | header()->setContextMenuPolicy(Qt::CustomContextMenu); |
37 | connect(header(), &QHeaderView::customContextMenuRequested, this, &CommitHistoryView::onHeaderContextMenu); |
38 | |
39 | connect(mCache.get(), &GitCache::signalCacheUpdated, this, &CommitHistoryView::refreshView); |
40 | |
41 | connect(this, &CommitHistoryView::doubleClicked, this, [this](const QModelIndex &index) { |
42 | if (mCommitHistoryModel) |
43 | { |
44 | const auto sha = mCommitHistoryModel->sha(index.row()); |
45 | emit signalOpenDiff(sha); |
46 | } |
47 | }); |
48 | } |
49 | |
50 | void CommitHistoryView::setModel(QAbstractItemModel *model) |
51 | { |
52 | connect(this, &CommitHistoryView::customContextMenuRequested, this, &CommitHistoryView::showContextMenu, |
53 | Qt::UniqueConnection); |
54 | |
55 | mCommitHistoryModel = dynamic_cast<CommitHistoryModel *>(model); |
56 | QTreeView::setModel(model); |
57 | setupGeometry(); |
58 | connect(this->selectionModel(), &QItemSelectionModel::selectionChanged, this, |
59 | [this](const QItemSelection &selected, const QItemSelection &) { |
60 | const auto indexes = selected.indexes(); |
61 | if (!indexes.isEmpty()) |
62 | { |
63 | scrollTo(indexes.first()); |
64 | emit clicked(indexes.first()); |
65 | } |
66 | }); |
67 | } |
68 | |
69 | void CommitHistoryView::filterBySha(const QStringList &shaList) |
70 | { |
71 | mIsFiltering = true; |
72 | |
73 | if (mProxyModel) |
74 | { |
75 | mProxyModel->beginResetModel(); |
76 | mProxyModel->setAcceptedSha(shaList); |
77 | mProxyModel->endResetModel(); |
78 | } |
79 | else |
80 | { |
81 | mProxyModel = new ShaFilterProxyModel(this); |
82 | mProxyModel->setSourceModel(mCommitHistoryModel); |
83 | mProxyModel->setAcceptedSha(shaList); |
84 | setModel(mProxyModel); |
85 | } |
86 | |
87 | setupGeometry(); |
88 | } |
89 | |
90 | CommitHistoryView::~CommitHistoryView() |
91 | { |
92 | mSettings->setLocalValue(QString("%1" ).arg(objectName()), header()->saveState()); |
93 | } |
94 | |
95 | void CommitHistoryView::setupGeometry() |
96 | { |
97 | const auto previousState = mSettings->localValue(QString("%1" ).arg(objectName()), QByteArray()).toByteArray(); |
98 | |
99 | if (previousState.isEmpty()) |
100 | { |
101 | const auto hv = header(); |
102 | hv->setMinimumSectionSize(75); |
103 | hv->resizeSection(static_cast<int>(CommitHistoryColumns::Sha), 75); |
104 | hv->resizeSection(static_cast<int>(CommitHistoryColumns::Graph), 120); |
105 | hv->resizeSection(static_cast<int>(CommitHistoryColumns::Author), 160); |
106 | hv->resizeSection(static_cast<int>(CommitHistoryColumns::Date), 125); |
107 | hv->resizeSection(static_cast<int>(CommitHistoryColumns::Sha), 75); |
108 | hv->setSectionResizeMode(static_cast<int>(CommitHistoryColumns::Author), QHeaderView::Fixed); |
109 | hv->setSectionResizeMode(static_cast<int>(CommitHistoryColumns::Date), QHeaderView::Fixed); |
110 | hv->setSectionResizeMode(static_cast<int>(CommitHistoryColumns::Sha), QHeaderView::Fixed); |
111 | hv->setSectionResizeMode(static_cast<int>(CommitHistoryColumns::Log), QHeaderView::Stretch); |
112 | hv->setStretchLastSection(false); |
113 | |
114 | hideColumn(static_cast<int>(CommitHistoryColumns::TreeViewIcon)); |
115 | } |
116 | else |
117 | { |
118 | header()->restoreState(previousState); |
119 | header()->setSectionResizeMode(static_cast<int>(CommitHistoryColumns::Log), QHeaderView::Stretch); |
120 | } |
121 | } |
122 | |
123 | void CommitHistoryView::currentChanged(const QModelIndex &index, const QModelIndex &) |
124 | { |
125 | mCurrentSha = model()->index(index.row(), static_cast<int>(CommitHistoryColumns::Sha)).data().toString(); |
126 | } |
127 | |
128 | void CommitHistoryView::refreshView() |
129 | { |
130 | QModelIndex topLeft; |
131 | QModelIndex bottomRight; |
132 | |
133 | if (mProxyModel) |
134 | { |
135 | topLeft = mProxyModel->index(0, 0); |
136 | bottomRight = mProxyModel->index(mProxyModel->rowCount() - 1, mProxyModel->columnCount() - 1); |
137 | mProxyModel->beginResetModel(); |
138 | mProxyModel->endResetModel(); |
139 | } |
140 | else |
141 | { |
142 | topLeft = mCommitHistoryModel->index(0, 0); |
143 | bottomRight |
144 | = mCommitHistoryModel->index(mCommitHistoryModel->rowCount() - 1, mCommitHistoryModel->columnCount() - 1); |
145 | mCommitHistoryModel->onNewRevisions(mCache->commitCount()); |
146 | } |
147 | |
148 | const auto auxTL = visualRect(topLeft); |
149 | const auto auxBR = visualRect(bottomRight); |
150 | viewport()->update(auxTL.x(), auxTL.y(), auxBR.x() + auxBR.width(), auxBR.y() + auxBR.height()); |
151 | } |
152 | |
153 | void CommitHistoryView::(const QPoint &pos) |
154 | { |
155 | const auto = new QMenu(this); |
156 | const auto total = header()->count(); |
157 | |
158 | for (auto column = 3; column < total; ++column) |
159 | { |
160 | const auto columnName = model()->headerData(column, Qt::Horizontal, Qt::DisplayRole).toString(); |
161 | const auto action = menu->addAction(columnName); |
162 | const auto isHidden = isColumnHidden(column); |
163 | action->setCheckable(true); |
164 | action->setChecked(!isHidden); |
165 | connect(action, &QAction::triggered, this, [column, this, action]() { |
166 | action->setChecked(!action->isChecked()); |
167 | setColumnHidden(column, !isColumnHidden(column)); |
168 | }); |
169 | } |
170 | |
171 | menu->exec(header()->mapToGlobal(pos)); |
172 | } |
173 | |
174 | void CommitHistoryView::clear() |
175 | { |
176 | mCommitHistoryModel->clear(); |
177 | } |
178 | |
179 | void CommitHistoryView::focusOnCommit(const QString &goToSha) |
180 | { |
181 | mCurrentSha = goToSha; |
182 | |
183 | QLog_Info("UI" , QString("Setting the focus on the commit {%1}" ).arg(mCurrentSha)); |
184 | |
185 | auto row = mCache->commitInfo(mCurrentSha).pos; |
186 | |
187 | if (mIsFiltering) |
188 | { |
189 | const auto sourceIndex = mProxyModel->sourceModel()->index(row, 0); |
190 | row = mProxyModel->mapFromSource(sourceIndex).row(); |
191 | } |
192 | |
193 | clearSelection(); |
194 | |
195 | const auto index = model()->index(row, 0); |
196 | |
197 | setCurrentIndex(index); |
198 | scrollTo(currentIndex()); |
199 | } |
200 | |
201 | QModelIndexList CommitHistoryView::selectedIndexes() const |
202 | { |
203 | return QTreeView::selectedIndexes(); |
204 | } |
205 | |
206 | void CommitHistoryView::(const QPoint &pos) |
207 | { |
208 | if (!mIsFiltering) |
209 | { |
210 | const auto shas = getSelectedShaList(); |
211 | |
212 | if (!shas.isEmpty()) |
213 | { |
214 | const auto = new CommitHistoryContextMenu(mCache, mGit, mGitServerCache, shas, this); |
215 | connect(menu, &CommitHistoryContextMenu::fullReload, this, &CommitHistoryView::fullReload); |
216 | connect(menu, &CommitHistoryContextMenu::referencesReload, this, &CommitHistoryView::referencesReload); |
217 | connect(menu, &CommitHistoryContextMenu::logReload, this, &CommitHistoryView::logReload); |
218 | connect(menu, &CommitHistoryContextMenu::signalOpenDiff, this, &CommitHistoryView::signalOpenDiff); |
219 | connect(menu, &CommitHistoryContextMenu::signalOpenCompareDiff, this, |
220 | &CommitHistoryView::signalOpenCompareDiff); |
221 | connect(menu, &CommitHistoryContextMenu::signalAmendCommit, this, &CommitHistoryView::signalAmendCommit); |
222 | connect(menu, &CommitHistoryContextMenu::signalMergeRequired, this, &CommitHistoryView::signalMergeRequired); |
223 | connect(menu, &CommitHistoryContextMenu::mergeSqushRequested, this, &CommitHistoryView::mergeSqushRequested); |
224 | connect(menu, &CommitHistoryContextMenu::signalCherryPickConflict, this, |
225 | &CommitHistoryView::signalCherryPickConflict); |
226 | connect(menu, &CommitHistoryContextMenu::signalPullConflict, this, &CommitHistoryView::signalPullConflict); |
227 | connect(menu, &CommitHistoryContextMenu::showPrDetailedView, this, &CommitHistoryView::showPrDetailedView); |
228 | menu->exec(viewport()->mapToGlobal(pos)); |
229 | } |
230 | else |
231 | QLog_Warning("UI" , "SHAs selected belong to different branches. They need to share at least one branch." ); |
232 | } |
233 | } |
234 | |
235 | QStringList CommitHistoryView::getSelectedShaList() const |
236 | { |
237 | const auto indexes = selectedIndexes(); |
238 | |
239 | if (indexes.count() > 0) |
240 | { |
241 | QMap<QDateTime, QString> shas; |
242 | |
243 | for (auto index : indexes) |
244 | { |
245 | const auto sha = mCommitHistoryModel->sha(index.row()); |
246 | const auto dtStr |
247 | = mCommitHistoryModel->index(index.row(), static_cast<int>(CommitHistoryColumns::Date)).data().toString(); |
248 | |
249 | shas.insert(QDateTime::fromString(dtStr, "dd MMM yyyy hh:mm" ), sha); |
250 | } |
251 | |
252 | return shas.values(); |
253 | } |
254 | |
255 | return QStringList(); |
256 | } |
257 | |