| 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 | |