| 1 | #include "HistoryWidget.h" |
| 2 | |
| 3 | #include <AmendWidget.h> |
| 4 | #include <BranchesWidget.h> |
| 5 | #include <CheckBox.h> |
| 6 | #include <CommitHistoryModel.h> |
| 7 | #include <CommitHistoryView.h> |
| 8 | #include <CommitInfo.h> |
| 9 | #include <CommitInfoWidget.h> |
| 10 | #include <FileDiffWidget.h> |
| 11 | #include <FileEditor.h> |
| 12 | #include <FullDiffWidget.h> |
| 13 | #include <GitBase.h> |
| 14 | #include <GitBranches.h> |
| 15 | #include <GitCache.h> |
| 16 | #include <GitConfig.h> |
| 17 | #include <GitHistory.h> |
| 18 | #include <GitLocal.h> |
| 19 | #include <GitMerge.h> |
| 20 | #include <GitQlientSettings.h> |
| 21 | #include <GitQlientStyles.h> |
| 22 | #include <GitRemote.h> |
| 23 | #include <GitRepoLoader.h> |
| 24 | #include <GitWip.h> |
| 25 | #include <RepositoryViewDelegate.h> |
| 26 | #include <WipWidget.h> |
| 27 | |
| 28 | #include <QLogger.h> |
| 29 | |
| 30 | #include <QApplication> |
| 31 | #include <QGridLayout> |
| 32 | #include <QLabel> |
| 33 | #include <QLineEdit> |
| 34 | #include <QMenu> |
| 35 | #include <QMessageBox> |
| 36 | #include <QPushButton> |
| 37 | #include <QScreen> |
| 38 | #include <QSplitter> |
| 39 | #include <QStackedWidget> |
| 40 | |
| 41 | using namespace QLogger; |
| 42 | |
| 43 | HistoryWidget::HistoryWidget(const QSharedPointer<GitCache> &cache, const QSharedPointer<GitBase> git, |
| 44 | const QSharedPointer<GitServerCache> &gitServerCache, |
| 45 | const QSharedPointer<GitQlientSettings> &settings, QWidget *parent) |
| 46 | : QFrame(parent) |
| 47 | , mGit(git) |
| 48 | , mCache(cache) |
| 49 | , mGitServerCache(gitServerCache) |
| 50 | , mSettings(settings) |
| 51 | , mWipWidget(new WipWidget(mCache, mGit)) |
| 52 | , mAmendWidget(new AmendWidget(mCache, mGit)) |
| 53 | , mCommitInfoWidget(new CommitInfoWidget(mCache, mGit)) |
| 54 | , mReturnFromFull(new QPushButton()) |
| 55 | , mUserName(new QLabel()) |
| 56 | , mUserEmail(new QLabel()) |
| 57 | , mSplitter(new QSplitter()) |
| 58 | { |
| 59 | setAttribute(Qt::WA_DeleteOnClose); |
| 60 | |
| 61 | QScopedPointer<GitConfig> gitConfig(new GitConfig(mGit)); |
| 62 | const auto localUserInfo = gitConfig->getLocalUserInfo(); |
| 63 | const auto globalUserInfo = gitConfig->getGlobalUserInfo(); |
| 64 | |
| 65 | mUserName->setText(localUserInfo.mUserName.isEmpty() ? globalUserInfo.mUserName : localUserInfo.mUserName); |
| 66 | mUserEmail->setText(localUserInfo.mUserEmail.isEmpty() ? globalUserInfo.mUserEmail : localUserInfo.mUserEmail); |
| 67 | |
| 68 | const auto wipInfoFrame = new QFrame(); |
| 69 | wipInfoFrame->setObjectName("wipInfoFrame" ); |
| 70 | const auto wipInfoLayout = new QVBoxLayout(wipInfoFrame); |
| 71 | wipInfoLayout->setContentsMargins(QMargins()); |
| 72 | wipInfoLayout->setSpacing(10); |
| 73 | wipInfoLayout->addWidget(mUserName); |
| 74 | wipInfoLayout->addWidget(mUserEmail); |
| 75 | |
| 76 | mCommitStackedWidget = new QStackedWidget(); |
| 77 | mCommitStackedWidget->setCurrentIndex(0); |
| 78 | mCommitStackedWidget->addWidget(mCommitInfoWidget); |
| 79 | mCommitStackedWidget->addWidget(mWipWidget); |
| 80 | mCommitStackedWidget->addWidget(mAmendWidget); |
| 81 | |
| 82 | const auto wipLayout = new QVBoxLayout(); |
| 83 | wipLayout->setContentsMargins(QMargins()); |
| 84 | wipLayout->setSpacing(5); |
| 85 | wipLayout->addWidget(wipInfoFrame); |
| 86 | wipLayout->addWidget(mCommitStackedWidget); |
| 87 | |
| 88 | const auto wipFrame = new QFrame(); |
| 89 | wipFrame->setLayout(wipLayout); |
| 90 | wipFrame->setMinimumWidth(200); |
| 91 | wipFrame->setMaximumWidth(500); |
| 92 | |
| 93 | connect(mWipWidget, &CommitChangesWidget::signalShowDiff, this, &HistoryWidget::showFileDiff); |
| 94 | connect(mWipWidget, &CommitChangesWidget::changesCommitted, this, &HistoryWidget::returnToView); |
| 95 | connect(mWipWidget, &CommitChangesWidget::changesCommitted, this, &HistoryWidget::changesCommitted); |
| 96 | connect(mWipWidget, &CommitChangesWidget::changesCommitted, this, &HistoryWidget::cleanCommitPanels); |
| 97 | connect(mWipWidget, &CommitChangesWidget::signalCheckoutPerformed, this, &HistoryWidget::onRevertedChanges); |
| 98 | connect(mWipWidget, &CommitChangesWidget::signalShowFileHistory, this, &HistoryWidget::signalShowFileHistory); |
| 99 | connect(mWipWidget, &CommitChangesWidget::signalUpdateWip, this, &HistoryWidget::signalUpdateWip); |
| 100 | connect(mWipWidget, &CommitChangesWidget::changeReverted, this, [this](const QString &revertedFile) { |
| 101 | if (mFileDiff->getCurrentFile().contains(revertedFile)) |
| 102 | { |
| 103 | returnToView(); |
| 104 | onRevertedChanges(); |
| 105 | } |
| 106 | }); |
| 107 | |
| 108 | connect(mAmendWidget, &CommitChangesWidget::logReload, this, &HistoryWidget::logReload); |
| 109 | connect(mAmendWidget, &CommitChangesWidget::signalShowDiff, this, &HistoryWidget::showFileDiff); |
| 110 | connect(mAmendWidget, &CommitChangesWidget::changesCommitted, this, &HistoryWidget::returnToView); |
| 111 | connect(mAmendWidget, &CommitChangesWidget::changesCommitted, this, &HistoryWidget::changesCommitted); |
| 112 | connect(mAmendWidget, &CommitChangesWidget::changesCommitted, this, &HistoryWidget::cleanCommitPanels); |
| 113 | connect(mAmendWidget, &CommitChangesWidget::signalCheckoutPerformed, this, &HistoryWidget::onRevertedChanges); |
| 114 | connect(mAmendWidget, &CommitChangesWidget::signalShowFileHistory, this, &HistoryWidget::signalShowFileHistory); |
| 115 | connect(mAmendWidget, &CommitChangesWidget::signalUpdateWip, this, &HistoryWidget::signalUpdateWip); |
| 116 | connect(mAmendWidget, &CommitChangesWidget::signalCancelAmend, this, &HistoryWidget::selectCommit); |
| 117 | |
| 118 | connect(mCommitInfoWidget, &CommitInfoWidget::signalOpenFileCommit, this, &HistoryWidget::showFileDiff); |
| 119 | connect(mCommitInfoWidget, &CommitInfoWidget::signalShowFileHistory, this, &HistoryWidget::signalShowFileHistory); |
| 120 | |
| 121 | mSearchInput = new QLineEdit(); |
| 122 | mSearchInput->setObjectName("SearchInput" ); |
| 123 | mSearchInput->setPlaceholderText(tr("Press Enter to search by SHA or log message..." )); |
| 124 | connect(mSearchInput, &QLineEdit::returnPressed, this, &HistoryWidget::search); |
| 125 | |
| 126 | mRepositoryModel = new CommitHistoryModel(mCache, mGit, mGitServerCache); |
| 127 | mRepositoryView = new CommitHistoryView(mCache, mGit, mSettings, mGitServerCache); |
| 128 | |
| 129 | connect(mRepositoryView, &CommitHistoryView::fullReload, this, &HistoryWidget::fullReload); |
| 130 | connect(mRepositoryView, &CommitHistoryView::referencesReload, this, &HistoryWidget::referencesReload); |
| 131 | connect(mRepositoryView, &CommitHistoryView::logReload, this, &HistoryWidget::logReload); |
| 132 | |
| 133 | connect(mRepositoryView, &CommitHistoryView::signalOpenDiff, this, &HistoryWidget::onOpenFullDiff); |
| 134 | connect(mRepositoryView, &CommitHistoryView::signalOpenCompareDiff, this, &HistoryWidget::signalOpenCompareDiff); |
| 135 | connect(mRepositoryView, &CommitHistoryView::clicked, this, &HistoryWidget::commitSelected); |
| 136 | connect(mRepositoryView, &CommitHistoryView::customContextMenuRequested, this, [this](const QPoint &pos) { |
| 137 | const auto rowIndex = mRepositoryView->indexAt(pos); |
| 138 | commitSelected(rowIndex); |
| 139 | }); |
| 140 | connect(mRepositoryView, &CommitHistoryView::signalAmendCommit, this, &HistoryWidget::onAmendCommit); |
| 141 | connect(mRepositoryView, &CommitHistoryView::signalMergeRequired, this, &HistoryWidget::mergeBranch); |
| 142 | connect(mRepositoryView, &CommitHistoryView::mergeSqushRequested, this, &HistoryWidget::mergeSquashBranch); |
| 143 | connect(mRepositoryView, &CommitHistoryView::signalCherryPickConflict, this, |
| 144 | &HistoryWidget::signalCherryPickConflict); |
| 145 | connect(mRepositoryView, &CommitHistoryView::signalPullConflict, this, &HistoryWidget::signalPullConflict); |
| 146 | connect(mRepositoryView, &CommitHistoryView::showPrDetailedView, this, &HistoryWidget::showPrDetailedView); |
| 147 | |
| 148 | mRepositoryView->setObjectName("historyGraphView" ); |
| 149 | mRepositoryView->setModel(mRepositoryModel); |
| 150 | mRepositoryView->setItemDelegate(mItemDelegate |
| 151 | = new RepositoryViewDelegate(cache, mGit, mGitServerCache, mRepositoryView)); |
| 152 | mRepositoryView->setEnabled(true); |
| 153 | |
| 154 | mBranchesWidget = new BranchesWidget(mCache, mGit); |
| 155 | |
| 156 | connect(mBranchesWidget, &BranchesWidget::fullReload, this, &HistoryWidget::fullReload); |
| 157 | connect(mBranchesWidget, &BranchesWidget::logReload, this, &HistoryWidget::logReload); |
| 158 | |
| 159 | connect(mBranchesWidget, &BranchesWidget::signalSelectCommit, mRepositoryView, &CommitHistoryView::focusOnCommit); |
| 160 | connect(mBranchesWidget, &BranchesWidget::signalSelectCommit, this, &HistoryWidget::goToSha); |
| 161 | connect(mBranchesWidget, &BranchesWidget::signalOpenSubmodule, this, &HistoryWidget::signalOpenSubmodule); |
| 162 | connect(mBranchesWidget, &BranchesWidget::signalMergeRequired, this, &HistoryWidget::mergeBranch); |
| 163 | connect(mBranchesWidget, &BranchesWidget::mergeSqushRequested, this, &HistoryWidget::mergeSquashBranch); |
| 164 | connect(mBranchesWidget, &BranchesWidget::signalPullConflict, this, &HistoryWidget::signalPullConflict); |
| 165 | connect(mBranchesWidget, &BranchesWidget::panelsVisibilityChanged, this, &HistoryWidget::panelsVisibilityChanged); |
| 166 | |
| 167 | const auto cherryPickBtn = new QPushButton(tr("Cherry-pick" )); |
| 168 | cherryPickBtn->setEnabled(false); |
| 169 | cherryPickBtn->setObjectName("cherryPickBtn" ); |
| 170 | cherryPickBtn->setToolTip("Cherry-pick the commit" ); |
| 171 | connect(cherryPickBtn, &QPushButton::clicked, this, &HistoryWidget::cherryPickCommit); |
| 172 | connect(mSearchInput, &QLineEdit::textChanged, this, |
| 173 | [cherryPickBtn](const QString &text) { cherryPickBtn->setEnabled(!text.isEmpty()); }); |
| 174 | |
| 175 | mChShowAllBranches = new CheckBox(tr("Show all branches" )); |
| 176 | mChShowAllBranches->setChecked(mSettings->localValue("ShowAllBranches" , true).toBool()); |
| 177 | connect(mChShowAllBranches, &CheckBox::toggled, this, &HistoryWidget::onShowAllUpdated); |
| 178 | |
| 179 | const auto graphOptionsLayout = new QHBoxLayout(); |
| 180 | graphOptionsLayout->setContentsMargins(QMargins()); |
| 181 | graphOptionsLayout->setSpacing(10); |
| 182 | graphOptionsLayout->addWidget(mSearchInput); |
| 183 | graphOptionsLayout->addWidget(cherryPickBtn); |
| 184 | graphOptionsLayout->addWidget(mChShowAllBranches); |
| 185 | |
| 186 | const auto viewLayout = new QVBoxLayout(); |
| 187 | viewLayout->setContentsMargins(QMargins()); |
| 188 | viewLayout->setSpacing(5); |
| 189 | viewLayout->addLayout(graphOptionsLayout); |
| 190 | viewLayout->addWidget(mRepositoryView); |
| 191 | |
| 192 | mGraphFrame = new QFrame(); |
| 193 | mGraphFrame->setLayout(viewLayout); |
| 194 | |
| 195 | mFileDiff = new FileDiffWidget(mGit, mCache); |
| 196 | |
| 197 | mReturnFromFull->setIcon(QIcon(":/icons/back" )); |
| 198 | connect(mReturnFromFull, &QPushButton::clicked, this, &HistoryWidget::returnToView); |
| 199 | mFullDiffWidget = new FullDiffWidget(mGit, mCache); |
| 200 | |
| 201 | const auto fullFrame = new QFrame(); |
| 202 | const auto fullLayout = new QGridLayout(fullFrame); |
| 203 | fullLayout->setSpacing(10); |
| 204 | fullLayout->setContentsMargins(QMargins()); |
| 205 | fullLayout->addWidget(mReturnFromFull, 0, 0); |
| 206 | fullLayout->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed), 0, 1); |
| 207 | fullLayout->addWidget(mFullDiffWidget, 1, 0, 1, 2); |
| 208 | |
| 209 | mCenterStackedWidget = new QStackedWidget(); |
| 210 | mCenterStackedWidget->setMinimumWidth(600); |
| 211 | mCenterStackedWidget->insertWidget(static_cast<int>(Pages::Graph), mGraphFrame); |
| 212 | mCenterStackedWidget->insertWidget(static_cast<int>(Pages::FileDiff), mFileDiff); |
| 213 | mCenterStackedWidget->insertWidget(static_cast<int>(Pages::FullDiff), fullFrame); |
| 214 | |
| 215 | connect(mFileDiff, &FileDiffWidget::exitRequested, this, &HistoryWidget::returnToView); |
| 216 | connect(mFileDiff, &FileDiffWidget::fileStaged, this, &HistoryWidget::signalUpdateWip); |
| 217 | connect(mFileDiff, &FileDiffWidget::fileReverted, this, &HistoryWidget::signalUpdateWip); |
| 218 | |
| 219 | connect(mWipWidget, &WipWidget::signalEditFile, mFileDiff, [this](const QString &fileName) { |
| 220 | showFileDiffEdition(CommitInfo::ZERO_SHA, mCache->commitInfo(CommitInfo::ZERO_SHA).firstParent(), fileName); |
| 221 | }); |
| 222 | |
| 223 | mSplitter->insertWidget(0, wipFrame); |
| 224 | mSplitter->insertWidget(1, mCenterStackedWidget); |
| 225 | mSplitter->setCollapsible(1, false); |
| 226 | mSplitter->insertWidget(2, mBranchesWidget); |
| 227 | |
| 228 | const auto minimalActive = mBranchesWidget->isMinimalViewActive(); |
| 229 | const auto branchesWidth = minimalActive ? 50 : 200; |
| 230 | |
| 231 | rearrangeSplittrer(minimalActive); |
| 232 | |
| 233 | connect(mBranchesWidget, &BranchesWidget::minimalViewStateChanged, this, &HistoryWidget::rearrangeSplittrer); |
| 234 | |
| 235 | const auto splitterSate = mSettings->localValue("HistoryWidgetState" , QByteArray()).toByteArray(); |
| 236 | |
| 237 | if (splitterSate.isEmpty()) |
| 238 | mSplitter->setSizes({ 200, 500, branchesWidth }); |
| 239 | else |
| 240 | mSplitter->restoreState(splitterSate); |
| 241 | |
| 242 | const auto layout = new QHBoxLayout(this); |
| 243 | layout->setContentsMargins(QMargins()); |
| 244 | layout->addWidget(mSplitter); |
| 245 | |
| 246 | mCenterStackedWidget->setCurrentIndex(static_cast<int>(Pages::Graph)); |
| 247 | mCenterStackedWidget->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); |
| 248 | mBranchesWidget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding); |
| 249 | } |
| 250 | |
| 251 | HistoryWidget::~HistoryWidget() |
| 252 | { |
| 253 | mSettings->setLocalValue("HistoryWidgetState" , mSplitter->saveState()); |
| 254 | |
| 255 | delete mItemDelegate; |
| 256 | delete mRepositoryModel; |
| 257 | } |
| 258 | |
| 259 | void HistoryWidget::clear() |
| 260 | { |
| 261 | mRepositoryView->clear(); |
| 262 | resetWip(); |
| 263 | mBranchesWidget->clear(); |
| 264 | mCommitInfoWidget->clear(); |
| 265 | mAmendWidget->clear(); |
| 266 | |
| 267 | mCommitStackedWidget->setCurrentIndex(mCommitStackedWidget->currentIndex()); |
| 268 | } |
| 269 | |
| 270 | void HistoryWidget::resetWip() |
| 271 | { |
| 272 | mWipWidget->clear(); |
| 273 | } |
| 274 | |
| 275 | void HistoryWidget::loadBranches(bool fullReload) |
| 276 | { |
| 277 | if (fullReload) |
| 278 | mBranchesWidget->showBranches(); |
| 279 | else |
| 280 | mBranchesWidget->refreshCurrentBranchLink(); |
| 281 | } |
| 282 | |
| 283 | void HistoryWidget::updateUiFromWatcher() |
| 284 | { |
| 285 | if (const auto widget = dynamic_cast<CommitChangesWidget *>(mCommitStackedWidget->currentWidget())) |
| 286 | widget->reload(); |
| 287 | |
| 288 | if (const auto widget = dynamic_cast<IDiffWidget *>(mCenterStackedWidget->currentWidget())) |
| 289 | widget->reload(); |
| 290 | } |
| 291 | |
| 292 | void HistoryWidget::focusOnCommit(const QString &sha) |
| 293 | { |
| 294 | mRepositoryView->focusOnCommit(sha); |
| 295 | } |
| 296 | |
| 297 | void HistoryWidget::updateGraphView(int totalCommits) |
| 298 | { |
| 299 | mRepositoryModel->onNewRevisions(totalCommits); |
| 300 | |
| 301 | selectCommit(CommitInfo::ZERO_SHA); |
| 302 | |
| 303 | mRepositoryView->selectionModel()->select( |
| 304 | QItemSelection(mRepositoryModel->index(0, 0), mRepositoryModel->index(0, mRepositoryModel->columnCount() - 1)), |
| 305 | QItemSelectionModel::Select); |
| 306 | } |
| 307 | |
| 308 | void HistoryWidget::keyPressEvent(QKeyEvent *event) |
| 309 | { |
| 310 | if (event->key() == Qt::Key_Shift) |
| 311 | mReverseSearch = true; |
| 312 | |
| 313 | QFrame::keyPressEvent(event); |
| 314 | } |
| 315 | |
| 316 | void HistoryWidget::keyReleaseEvent(QKeyEvent *event) |
| 317 | { |
| 318 | if (event->key() == Qt::Key_Shift) |
| 319 | mReverseSearch = false; |
| 320 | |
| 321 | QFrame::keyReleaseEvent(event); |
| 322 | } |
| 323 | |
| 324 | void HistoryWidget::onOpenFullDiff(const QString &sha) |
| 325 | { |
| 326 | if (sha == CommitInfo::ZERO_SHA) |
| 327 | { |
| 328 | const auto commit = mCache->commitInfo(CommitInfo::ZERO_SHA); |
| 329 | QScopedPointer<GitHistory> git(new GitHistory(mGit)); |
| 330 | const auto ret = git->getCommitDiff(CommitInfo::ZERO_SHA, commit.firstParent()); |
| 331 | |
| 332 | if (ret.success && !ret.output.isEmpty()) |
| 333 | { |
| 334 | mFullDiffWidget->loadDiff(CommitInfo::ZERO_SHA, commit.firstParent(), ret.output); |
| 335 | mCenterStackedWidget->setCurrentIndex(static_cast<int>(Pages::FullDiff)); |
| 336 | } |
| 337 | else |
| 338 | QMessageBox::warning(this, tr("No diff available!" ), tr("There is no diff to show." )); |
| 339 | } |
| 340 | else |
| 341 | emit signalOpenDiff(sha); |
| 342 | } |
| 343 | |
| 344 | void HistoryWidget::rearrangeSplittrer(bool minimalActive) |
| 345 | { |
| 346 | if (minimalActive) |
| 347 | { |
| 348 | mBranchesWidget->setFixedWidth(50); |
| 349 | mSplitter->setCollapsible(2, false); |
| 350 | } |
| 351 | else |
| 352 | { |
| 353 | mBranchesWidget->setMinimumWidth(250); |
| 354 | mBranchesWidget->setMaximumWidth(500); |
| 355 | mSplitter->setCollapsible(2, true); |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | void HistoryWidget::cleanCommitPanels() |
| 360 | { |
| 361 | mWipWidget->clearStaged(); |
| 362 | mAmendWidget->clearStaged(); |
| 363 | } |
| 364 | |
| 365 | void HistoryWidget::onRevertedChanges() |
| 366 | { |
| 367 | QScopedPointer<GitWip> git(new GitWip(mGit, mCache)); |
| 368 | git->updateWip(); |
| 369 | |
| 370 | updateUiFromWatcher(); |
| 371 | } |
| 372 | |
| 373 | void HistoryWidget::onCommitTitleMaxLenghtChanged() |
| 374 | { |
| 375 | mWipWidget->setCommitTitleMaxLength(); |
| 376 | mAmendWidget->setCommitTitleMaxLength(); |
| 377 | } |
| 378 | |
| 379 | void HistoryWidget::onPanelsVisibilityChanged() |
| 380 | { |
| 381 | mBranchesWidget->onPanelsVisibilityChaned(); |
| 382 | } |
| 383 | |
| 384 | void HistoryWidget::search() |
| 385 | { |
| 386 | if (const auto text = mSearchInput->text(); !text.isEmpty()) |
| 387 | { |
| 388 | auto commitInfo = mCache->commitInfo(text); |
| 389 | |
| 390 | if (commitInfo.isValid()) |
| 391 | goToSha(text); |
| 392 | else |
| 393 | { |
| 394 | auto selectedItems = mRepositoryView->selectedIndexes(); |
| 395 | auto startingRow = 0; |
| 396 | |
| 397 | if (!selectedItems.isEmpty()) |
| 398 | { |
| 399 | std::sort(selectedItems.begin(), selectedItems.end(), |
| 400 | [](const QModelIndex index1, const QModelIndex index2) { return index1.row() <= index2.row(); }); |
| 401 | startingRow = selectedItems.constFirst().row(); |
| 402 | } |
| 403 | |
| 404 | commitInfo = mCache->searchCommitInfo(text, startingRow + 1, mReverseSearch); |
| 405 | |
| 406 | if (commitInfo.isValid()) |
| 407 | goToSha(commitInfo.sha); |
| 408 | else |
| 409 | QMessageBox::information(this, tr("Not found!" ), tr("No commits where found based on the search text." )); |
| 410 | } |
| 411 | } |
| 412 | } |
| 413 | |
| 414 | void HistoryWidget::goToSha(const QString &sha) |
| 415 | { |
| 416 | mRepositoryView->focusOnCommit(sha); |
| 417 | |
| 418 | selectCommit(sha); |
| 419 | } |
| 420 | |
| 421 | void HistoryWidget::commitSelected(const QModelIndex &index) |
| 422 | { |
| 423 | const auto sha = mRepositoryModel->sha(index.row()); |
| 424 | |
| 425 | selectCommit(sha); |
| 426 | } |
| 427 | |
| 428 | void HistoryWidget::onShowAllUpdated(bool showAll) |
| 429 | { |
| 430 | GitQlientSettings settings(mGit->getGitDir()); |
| 431 | settings.setLocalValue("ShowAllBranches" , showAll); |
| 432 | |
| 433 | emit signalAllBranchesActive(showAll); |
| 434 | emit logReload(); |
| 435 | } |
| 436 | |
| 437 | void HistoryWidget::mergeBranch(const QString ¤t, const QString &branchToMerge) |
| 438 | { |
| 439 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
| 440 | QScopedPointer<GitMerge> git(new GitMerge(mGit, mCache)); |
| 441 | const auto ret = git->merge(current, { branchToMerge }); |
| 442 | |
| 443 | QScopedPointer<GitWip> gitWip(new GitWip(mGit, mCache)); |
| 444 | gitWip->updateWip(); |
| 445 | |
| 446 | QApplication::restoreOverrideCursor(); |
| 447 | |
| 448 | processMergeResponse(ret); |
| 449 | } |
| 450 | |
| 451 | void HistoryWidget::mergeSquashBranch(const QString ¤t, const QString &branchToMerge) |
| 452 | { |
| 453 | QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); |
| 454 | QScopedPointer<GitMerge> git(new GitMerge(mGit, mCache)); |
| 455 | const auto ret = git->squashMerge(current, { branchToMerge }); |
| 456 | |
| 457 | QScopedPointer<GitWip> gitWip(new GitWip(mGit, mCache)); |
| 458 | gitWip->updateWip(); |
| 459 | |
| 460 | QApplication::restoreOverrideCursor(); |
| 461 | |
| 462 | processMergeResponse(ret); |
| 463 | } |
| 464 | |
| 465 | void HistoryWidget::processMergeResponse(const GitExecResult &ret) |
| 466 | { |
| 467 | if (!ret.success) |
| 468 | { |
| 469 | QMessageBox msgBox( |
| 470 | QMessageBox::Critical, tr("Merge failed" ), |
| 471 | QString(tr("There were problems during the merge. Please, see the detailed description for more " |
| 472 | "information.<br><br>GitQlient will show the merge helper tool." )), |
| 473 | QMessageBox::Ok, this); |
| 474 | msgBox.setDetailedText(ret.output); |
| 475 | msgBox.setStyleSheet(GitQlientStyles::getStyles()); |
| 476 | msgBox.exec(); |
| 477 | |
| 478 | emit signalMergeConflicts(); |
| 479 | } |
| 480 | else |
| 481 | { |
| 482 | if (!ret.output.isEmpty()) |
| 483 | { |
| 484 | if (ret.output.contains("error: could not apply" , Qt::CaseInsensitive) |
| 485 | || ret.output.contains(" conflict" , Qt::CaseInsensitive)) |
| 486 | { |
| 487 | QMessageBox msgBox( |
| 488 | QMessageBox::Warning, tr("Merge status" ), |
| 489 | tr("There were problems during the merge. Please, see the detailed description for more information." ), |
| 490 | QMessageBox::Ok, this); |
| 491 | msgBox.setDetailedText(ret.output); |
| 492 | msgBox.setStyleSheet(GitQlientStyles::getStyles()); |
| 493 | msgBox.exec(); |
| 494 | |
| 495 | emit signalMergeConflicts(); |
| 496 | } |
| 497 | else |
| 498 | { |
| 499 | emit fullReload(); |
| 500 | |
| 501 | QMessageBox msgBox( |
| 502 | QMessageBox::Information, tr("Merge successful" ), |
| 503 | tr("The merge was successfully done. See the detailed description for more information." ), |
| 504 | QMessageBox::Ok, this); |
| 505 | msgBox.setDetailedText(ret.output); |
| 506 | msgBox.setStyleSheet(GitQlientStyles::getStyles()); |
| 507 | msgBox.exec(); |
| 508 | } |
| 509 | } |
| 510 | } |
| 511 | } |
| 512 | |
| 513 | void HistoryWidget::selectCommit(const QString &goToSha) |
| 514 | { |
| 515 | const auto isWip = goToSha == CommitInfo::ZERO_SHA; |
| 516 | mCommitStackedWidget->setCurrentIndex(isWip); |
| 517 | |
| 518 | QLog_Info("UI" , QString("Selected commit {%1}" ).arg(goToSha)); |
| 519 | |
| 520 | if (isWip) |
| 521 | mWipWidget->reload(); |
| 522 | else |
| 523 | mCommitInfoWidget->configure(goToSha); |
| 524 | } |
| 525 | |
| 526 | void HistoryWidget::onAmendCommit(const QString &sha) |
| 527 | { |
| 528 | mCommitStackedWidget->setCurrentIndex(2); |
| 529 | mAmendWidget->configure(sha); |
| 530 | } |
| 531 | |
| 532 | void HistoryWidget::returnToView() |
| 533 | { |
| 534 | mCenterStackedWidget->setCurrentIndex(static_cast<int>(Pages::Graph)); |
| 535 | mBranchesWidget->returnToSavedView(); |
| 536 | } |
| 537 | |
| 538 | void HistoryWidget::cherryPickCommit() |
| 539 | { |
| 540 | if (auto commit = mCache->commitInfo(mSearchInput->text()); commit.isValid()) |
| 541 | { |
| 542 | const auto lastShaBeforeCommit = mGit->getLastCommit().output.trimmed(); |
| 543 | const auto git = QScopedPointer<GitLocal>(new GitLocal(mGit)); |
| 544 | const auto ret = git->cherryPickCommit(commit.sha); |
| 545 | |
| 546 | if (ret.success) |
| 547 | { |
| 548 | mSearchInput->clear(); |
| 549 | |
| 550 | commit.sha = mGit->getLastCommit().output.trimmed(); |
| 551 | |
| 552 | mCache->insertCommit(commit); |
| 553 | mCache->deleteReference(lastShaBeforeCommit, References::Type::LocalBranch, mGit->getCurrentBranch()); |
| 554 | mCache->insertReference(commit.sha, References::Type::LocalBranch, mGit->getCurrentBranch()); |
| 555 | |
| 556 | QScopedPointer<GitHistory> gitHistory(new GitHistory(mGit)); |
| 557 | const auto ret = gitHistory->getDiffFiles(commit.sha, lastShaBeforeCommit); |
| 558 | |
| 559 | mCache->insertRevisionFiles(commit.sha, lastShaBeforeCommit, RevisionFiles(ret.output)); |
| 560 | |
| 561 | emit mCache->signalCacheUpdated(); |
| 562 | emit logReload(); |
| 563 | } |
| 564 | else |
| 565 | { |
| 566 | if (ret.output.contains("error: could not apply" , Qt::CaseInsensitive) |
| 567 | || ret.output.contains(" conflict" , Qt::CaseInsensitive)) |
| 568 | { |
| 569 | emit signalCherryPickConflict(QStringList()); |
| 570 | } |
| 571 | else |
| 572 | { |
| 573 | QMessageBox msgBox(QMessageBox::Critical, tr("Error while cherry-pick" ), |
| 574 | tr("There were problems during the cherry-pick operation. Please, see the detailed " |
| 575 | "description for more information." ), |
| 576 | QMessageBox::Ok, this); |
| 577 | msgBox.setDetailedText(ret.output); |
| 578 | msgBox.setStyleSheet(GitQlientStyles::getStyles()); |
| 579 | msgBox.exec(); |
| 580 | } |
| 581 | } |
| 582 | } |
| 583 | else |
| 584 | { |
| 585 | const auto git = QScopedPointer<GitLocal>(new GitLocal(mGit)); |
| 586 | const auto ret = git->cherryPickCommit(mSearchInput->text()); |
| 587 | |
| 588 | if (ret.success) |
| 589 | { |
| 590 | mSearchInput->clear(); |
| 591 | emit logReload(); |
| 592 | } |
| 593 | } |
| 594 | } |
| 595 | |
| 596 | void HistoryWidget::showFileDiff(const QString &sha, const QString &parentSha, const QString &fileName, bool isCached) |
| 597 | { |
| 598 | if (sha == CommitInfo::ZERO_SHA) |
| 599 | { |
| 600 | mFileDiff->configure(sha, parentSha, fileName, isCached); |
| 601 | mCenterStackedWidget->setCurrentIndex(static_cast<int>(Pages::FileDiff)); |
| 602 | mBranchesWidget->forceMinimalView(); |
| 603 | } |
| 604 | else |
| 605 | emit signalShowDiff(sha, parentSha, fileName, isCached); |
| 606 | } |
| 607 | |
| 608 | void HistoryWidget::showFileDiffEdition(const QString &sha, const QString &parentSha, const QString &fileName) |
| 609 | { |
| 610 | if (sha == CommitInfo::ZERO_SHA) |
| 611 | { |
| 612 | mFileDiff->configure(sha, parentSha, fileName, true); |
| 613 | mCenterStackedWidget->setCurrentIndex(static_cast<int>(Pages::FileDiff)); |
| 614 | mBranchesWidget->forceMinimalView(); |
| 615 | } |
| 616 | else |
| 617 | emit signalShowDiff(sha, parentSha, fileName, false); |
| 618 | } |
| 619 | |